I am trying to write a CFFI wrapper for CVODE Gallery Sundials . SWIG was choking on the Sundials headers, as they are quite interconnected, and SWIG was unable to find the correct headers, so I did it manually: a little complicated, but I succeeded.
Now I'm trying to check if it works correctly. For now, just create a "problem object" and delete it. This is where the problem begins. Thus, the "problem object" is allocated through the function
SUNDIALS_EXPORT void *CVodeCreate(int lmm, int iter);
Why did I create a wrapper:
(cffi:defcfun "CVodeCreate" :pointer (lmm :int) (iter :int))
PS. SUNDIALS_EXPORT
(at least on Unix) is basically nothing.
Now, to destroy an object, Sundials uses its own function:
SUNDIALS_EXPORT void CVodeFree(void **cvode_mem);
So, I need to pass a reference to the object created by CVodeCreate
. In C, if my memory is not to blame, I would do something like CVodeFree(&problem_object)
. In CL, I wrote this shell for a function:
(cffi:defcfun "CVodeFree" :void (cvode-mem :pointer))
So here COVDE-MEM
is a pointer to a pointer. The question is how to get the pointer of a pointer in CL / CFFI? Here is the beginning of the code:
(defvar *p* (cvodecreate 1 2))
(PS. Do not worry about the numbers passed to CVodeCreate
, they just tell you which methods to use, you still need to define constants to make it more readable)
So *P*
something like
#.(SB-SYS:INT-SAP #X7FFFE0007060)
If I pass it directly to CVODEFREE
, it will CVODEFREE
:
CL-USER> (cvodefree *p*) ; Evaluation aborted on #<SIMPLE-ERROR "bus error at #X~X" {1005EC9BD3}>.
I tried to skip (CFFI:POINTER-ADDRESS *P*)
, but this leads to a similar "bus error ..." (not even sure if this function returns what I need). I also tried to do (CFFI:MAKE-POINTER (CFFI:POINTER-ADDRESS *P*))
, again without success.
This question offers this approach:
(cffi:with-foreign-object (p :pointer) (setf (cffi:mem-ref p :pointer) (cvodecreate 1 2)) (cvodefree p))
This works (at least it does not cause an error). I think I understand how this works: it creates (allocates memory for) a pointer to a pointer P
whose MEM-REF
(or in terms of C will be dereferenced *p
) is populated with the result on CVodeCreate
. Finally, I pass this pointer to a pointer to a CVODEFREE
that expects just that. Finally, the memory allocated for P
is freed upon completion of the form. Is this the right approach? And is this the only one I can accept?