<br>Hello,<br><br>&nbsp; I&#39;m having trouble using the foreign function interface.&nbsp; The<br>bug I have is strange, as I can only get it to occur in the context<br>of a larger program.&nbsp; 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>&nbsp; <br>&nbsp; I wanted to use a C program called CFSQP, a nonlinear optimization<br>package.&nbsp; 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>&nbsp; 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.&nbsp; The problem I face with MLton is that the functions<br>need to take arrays of doubles.&nbsp; Since these must be allocated<br>in the ML heap, I&#39;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>&nbsp; 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&#39;s simple enough now for someone to see my mistake.<br><br>structure Cfsqp :&gt; CFSQP =<br>struct <br><br>&nbsp; structure A = Array<br>
<br>&nbsp; type opt = {obj_fun : real array -&gt; real,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constr_fun : int * real array -&gt; real,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num_constrs : int,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lower_bnds : real array,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; upper_bnds : real array}
<br><br>&nbsp; (* Here is the global array *)<br>&nbsp; val function_args : real array ref = ref (A.array(0,0.0))<br>&nbsp; (* Here is how we set the values from C *)<br>&nbsp; val mlton_set_arg = _export &quot;mlton_set_arg&quot; : (int * real -&gt; unit) -&gt; unit;
<br>&nbsp; fun set_fun (i,x) = A.update(!function_args,i,x)<br><br>&nbsp; (* The imported C function *)<br>&nbsp; val cfsqp_minimize = _import &quot;cfsqp_minimize&quot; : int -&gt; unit;<br><br>&nbsp; (* Calling it once *)<br>&nbsp; fun minimize_once {obj_fun,constr_fun,num_constrs,lower_bnds,upper_bnds} =
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val num_args = A.length lower_bnds<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val () = function_args := A.array(num_args,0.0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val _ = mlton_set_arg set_fun (* I tried this line both outside and inside this function *)
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val () = print &quot;minimizing sml...\n&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val () = cfsqp_minimize num_args (* segfault is always here, after the C function returns successfully *)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val () = print &quot;done minimizing sml...\n&quot;
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (0.0,!function_args)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br><br>&nbsp; (* Calling it lots of times exposes the segfault, usually around <br>&nbsp;&nbsp;&nbsp;&nbsp; the 100th iteration *)<br>&nbsp; fun minimize x : real * real array =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val repeat = 10000<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A.sub (A.tabulate(repeat,(fn _ =&gt; minimize_once x)),0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br><br>end<br><br>Here is the C code:<br><br><br>#include &quot;stdio.h&quot;<br>// the name of the exported header from MLton -stop ...
<br>#include &quot;cfsqp-sml.h&quot;<br><br>// copy a bunch of 0s to the MLton global real array<br>void copy_array_to_mlton_heap(int numargs)<br>{<br>&nbsp; int i;<br>&nbsp; for(i=0;i&lt;numargs;i++){<br>&nbsp;&nbsp;&nbsp; mlton_set_arg(i,0.0);<br>
&nbsp; }<br>&nbsp; return;<br>}<br><br>// do that 10 times, to expose the segfault<br>void cfsqp_minimize(Int32 numargs)&nbsp; &nbsp;<br>{<br>&nbsp; printf(&quot;minimizing C...\n&quot;);<br>&nbsp; int i;<br>&nbsp; for(i=1;i&lt;=10;i++){<br>&nbsp;&nbsp;&nbsp; copy_array_to_mlton_heap(numargs);
<br>&nbsp; }<br>&nbsp; printf(&quot;done minimizing C...\n&quot;);<br>&nbsp; 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.&nbsp; That
<br>would make the call to [mlton_set_arg] mess things<br>up if [mlton_set_arg] didn&#39;t get updated with the<br>new address.&nbsp; But it seems that the garbage collector<br>should inform, at least [set_fun], and thus this<br>
doesn&#39;t seem possible. &nbsp;<br><br>Any ideas?<br><br>Thanks,<br><br>Sean<br><br>