[cffi-devel] A question about memory management and garbage collection

nitralime nitralime at googlemail.com
Mon May 9 14:46:20 UTC 2011


On 05/09/2011 01:49 PM, Martin Simmons wrote:
>>>>>> On Sun, 08 May 2011 14:39:41 +0200, Nitralime  said:
>> Using a finalizer seems to be a possible way to go. But I'm not sure how
>> this can be done by just using the finalizer parameters "object" and
>> "function"
>> where "function" can't reliablely access "object" (cf. documentation of
>> finalizer
>> in "trivial-garbage"  package)!!
>>
>> Any help and feedback is very much appreciated!
> IMHO, attempting to transparently wrap a foreign object with a CLOS object is
> not a good design.
>
> Using a finalizer is dangerous because it is difficult to guarantee that the
> Lisp wrapper object is retained for the correct lifetime.
>
> For example, consider
>
> (defstruct table
>    foreign-pointer)
>
> (defun allocate-table ()
>    (make-table :foreign-pointer (foreign-allocate-table)))
>
> (defun allocate-and-munge-table ()
>    (let ((table (allocate-table)))
>      (foreign-munge-table (table-foreign-pointer table))))
>
> The compiler might not keep the variable "table" alive during the call to the
> foreign function foreign-munge-table.  As a result, the Lisp table object
> might be gc'ed in another thread while the foreign code is accessing it.
>
Consider the following sample (pseudo-)code:
----------------------------------------------------------
(defclass table ()
((table-pointer :initarg :handle :accessor handle-of)))

(defmethod initialize-instance :after ((self table) &key)
(let ((table-pointer (handle-of self)))
(tg:finalize self (lambda () (foreign-destroy-table table-pointer)))))

(defmethod get-row ((t table) index)
(transform-to-lisp-vector (foreign-get-row (hadle-of t) index)))

(defmethod move-to ((t table) index)
(foreign-move-to (handle-of t) index))
.....
----------------------------------------------------------

Now consider a function which creates a table instance
and puts it into a result plist (and has probabely some side effects):

(defun call-a-foreign-function (.....)
(let (....)
....
<call a foreign function which allocates a table object
and returns a-foreign-table-pointer>
....
(let ((result-table (make-instance 'table :handle a-foreign-table-pointer))
(...))
...
...
'(:id ...
:tab result-table
:msg ...
...))))

The question is now what will happen if you do just

(call-a-foreign-function ...)

or something like this

(getf (call-a-foreign-function ...) :id)

I assume that the unreachable object 'result-table' will be garbage 
collected,
and the finalization will free the corresponding C table object!

Do you see any misconception (resp. potential danger) here?

Regards
Nik

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/cffi-devel/attachments/20110509/6145a50c/attachment.html>


More information about the cffi-devel mailing list