<br>Hello,<br><br>  I'm having trouble using the foreign function interface.  The<br>bug I have is strange, as I can only get it to occur in the context<br>of a larger program.  I have spent some time simplifying the code
<br>in the hope that someone may explain why I am getting regular <br>segmentation faults.<br>  <br>  I wanted to use a C program called CFSQP, a nonlinear optimization<br>package.  Roughly, you give the program a function pointer representing
<br>the objective function and a function pointer representing the<br>constraints and some bounds, and CFSQP will return the optimum value<br>of the function satisfying the constraints within those bounds.<br><br>  I implemented bindings for CFSQP in OCaml with little trouble,
<br>and thus have confidence that in principle the SML-CFSQP connection<br>should work.  The problem I face with MLton is that the functions<br>need to take arrays of doubles.  Since these must be allocated<br>in the ML heap, I'm not sure how to create such arrays in C.
<br>The solution I came up with is to allocate a global array for<br>the arguments in ML, and to set the values from C, finally calling<br>the SML function on the global array. <br><br>  I kept getting segfaults though, so I simplified the code until
<br>it no longer does anything except modify that global argument array.<br>I figure it's simple enough now for someone to see my mistake.<br><br>structure Cfsqp :> CFSQP =<br>struct <br><br>  structure A = Array<br>
<br>  type opt = {obj_fun : real array -> real,<br>              constr_fun : int * real array -> real,<br>              num_constrs : int,<br>              lower_bnds : real array,<br>              upper_bnds : real array}
<br><br>  (* Here is the global array *)<br>  val function_args : real array ref = ref (A.array(0,0.0))<br>  (* Here is how we set the values from C *)<br>  val mlton_set_arg = _export "mlton_set_arg" : (int * real -> unit) -> unit;
<br>  fun set_fun (i,x) = A.update(!function_args,i,x)<br><br>  (* The imported C function *)<br>  val cfsqp_minimize = _import "cfsqp_minimize" : int -> unit;<br><br>  (* Calling it once *)<br>  fun minimize_once {obj_fun,constr_fun,num_constrs,lower_bnds,upper_bnds} =
<br>      let<br>        val num_args = A.length lower_bnds<br>        val () = function_args := A.array(num_args,0.0)<br>        val _ = mlton_set_arg set_fun (* I tried this line both outside and inside this function *)
<br>        val () = print "minimizing sml...\n"<br>        val () = cfsqp_minimize num_args (* segfault is always here, after the C function returns successfully *)<br>        val () = print "done minimizing sml...\n"
<br>      in<br>        (0.0,!function_args)<br>      end<br><br>  (* Calling it lots of times exposes the segfault, usually around <br>     the 100th iteration *)<br>  fun minimize x : real * real array =<br>      let<br>
        val repeat = 10000<br>      in<br>        A.sub (A.tabulate(repeat,(fn _ => minimize_once x)),0)<br>      end<br><br>end<br><br>Here is the C code:<br><br><br>#include "stdio.h"<br>// the name of the exported header from MLton -stop ...
<br>#include "cfsqp-sml.h"<br><br>// copy a bunch of 0s to the MLton global real array<br>void copy_array_to_mlton_heap(int numargs)<br>{<br>  int i;<br>  for(i=0;i<numargs;i++){<br>    mlton_set_arg(i,0.0);<br>
  }<br>  return;<br>}<br><br>// do that 10 times, to expose the segfault<br>void cfsqp_minimize(Int32 numargs)   <br>{<br>  printf("minimizing C...\n");<br>  int i;<br>  for(i=1;i<=10;i++){<br>    copy_array_to_mlton_heap(numargs);
<br>  }<br>  printf("done minimizing C...\n");<br>  return;<br>}<br><br>My only guess as to what may be happening is that<br>at some point the garbage collector is moving the<br>[function_args] ref or the actual array.  That
<br>would make the call to [mlton_set_arg] mess things<br>up if [mlton_set_arg] didn't get updated with the<br>new address.  But it seems that the garbage collector<br>should inform, at least [set_fun], and thus this<br>
doesn't seem possible.  <br><br>Any ideas?<br><br>Thanks,<br><br>Sean<br><br>