Search code examples
cocamlffi

OCaml return unboxed float from C function with bytecode compiler


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?


Solution

  • 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.