Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OCaml dynamically check for badly behaved native functions

Tags:

c

ocaml

Is it possible to check at runtime for badly-behaved native functions in OCaml? This would be useful in mixed C/OCaml projects.

When implementing an intrinsic OCaml function in C, care has to be taken to live in harmony with the runtime.

For instance, in the following example add in libadd intentionally does not use CAMLreturn as would be appropriate.

(* foo.ml *)
external add : int -> int -> int = "add";;

Printf.printf "%d\n" (add 4 5);;

and the C source file

// libadd.c
#include <caml/memory.h>
#include <caml/mlvalues.h>

CAMLprim value
add(value ml_x, value ml_y)
{
    CAMLparam2(ml_x, ml_y);
    long x = Long_val(ml_x);
    long y = Long_val(ml_y);
    // intentional mistake here
    // don't use CAMLreturn
    return Val_long(x + y);
}

If you compile this code using either OCaml compiler

$ ocamlopt foo.ml libadd.c
$ ocamlc -custom foo.ml libadd.c

Then a.out just prints 9 without complaint.

./a.out
9

Is there a way to get either compiler to emit additional checks around native function calls to check that the OCaml calling convention has been adhered to?

like image 212
Gregory Nisbet Avatar asked Jun 03 '18 04:06

Gregory Nisbet


2 Answers

ocaml does nothing wrt to this issue, the error relies in the C code that is compiled by gcc. And gcc cannot check that the return is compatible or not with Ocaml.

May be one way to limit mis-written C for Ocaml is to redefine return to avoid using it :

#define return _forbidden_

Your initial C code will fail to compile if you include those define in your code.

It does not solve the issue, but it may be useful to force the user to take care of the way the function shall return.

Another way is having a sanity script checking that any function whose return type is CAML* does not contain any return...

like image 83
Pierre G. Avatar answered Nov 16 '22 08:11

Pierre G.


The CAML macros are just simple preprocessor macros. You can always just write the underlying C code directly instead of using the macro. Nothing short of changing gcc to know about how to interface with ocaml will fix that.

There is one simple trick for matching BEGIN and END style macros though to fail if one of the two is forgotten accidentally. The trick is to have an opening { in the BEGIN macro and a closing } on the END macro. Forgetting one of them will give an error because then {} don't balance.

Problem is that a function can have multiple return statements making the use of unbalanced {} impossible.

like image 1
Goswin von Brederlow Avatar answered Nov 16 '22 09:11

Goswin von Brederlow