I have a very simple function that calls time(2)
in order to get the epoch time and returns it as an unboxed OCaml float.
The platform here is OS X 10.12.6 and I've tested using OCaml versions 4.03.0 and 4.04.0 .
Here is libunixtime.c
#define CAML_NAME_SPACE
#include <time.h>
#include <caml/memory.h>
#define IGNORE_UNUSED(x) ( (void)(x) )
CAMLprim double
ocaml_unixtime(value unit)
{
IGNORE_UNUSED(unit);
return (double) time(NULL);
}
The OCaml code, unixtime.ml
looks like this ... it returns an unboxed float and indicates to the compiler that it doesn't perform any OCaml-side allocations.
This function takes less than 5 arguments, so it seems like implementing it once and using that for both the byte code compiler and native compiler should be fine (https://caml.inria.fr/pub/docs/manual-ocaml/intfc.html#sec397).
external unixtime : unit -> (float [@unboxed]) =
"ocaml_unixtime" "ocaml_unixtime" [@@noalloc];;
let () = Printf.printf "%f\n" (unixtime ())
This example works fine with the native compiler (although I'm a little concerned that the cast to double
is not exactly the right thing to do but It Works On My Machine).
% ocamlopt unixtime.ml libunixtime.c
% ./a.out
1506195346.000000
However, when compiling with the bytecode compiler and attempting to run, I get a segfault immediately.
% ocamlc -custom unixtime.ml libunixtime.c
% ./a.out
Segmentation fault
Exit 139
Does the bytecode compiler not support unboxed floats? How do I figure out why the behavior differs between the bytecode and native compilers?
First, your code seems to be missing a CAMLparam
call for the unit
value. This is necessary so that the GC knows about it, see section 19.1.
But there's another more important bug: the bytecode version cannot use unboxed functions (section 19.10), so you'll have to provide an alternative implementation for the bytecode compiler that returns a boxed value using caml_copy_double
and CAMLreturn
.