[cffi-devel] A question about memory management and garbage collection
Martin Simmons
martin at lispworks.com
Mon May 9 16:44:58 UTC 2011
>>>>> On Mon, 09 May 2011 16:46:20 +0200, nitralime said:
>
> 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?
Your examples will be safe, but
(get-row (getf (call-a-foreign-function ...) :tab) 0)
might crash.
--
Martin Simmons
LispWorks Ltd
http://www.lispworks.com/
More information about the cffi-devel
mailing list