From: Chris Paine
Subject: Problem with string passing in Lucid CL Foreign Function Interface.
Date: 
Message-ID: <1994Mar30.165858.6146@upper.ist.co.uk>
I am calling a C function from Lisp using the Lucid foreign function
interface. One of the arguments is a string, and I specify :simple-string
as its type in the def-foreign-function form. The problem is that there
seems to be window such that a garbage collection can result in the
C function getting a pointer to rubbish because the garbage collector
has moved the lisp string (at least I think that this is what is
happening). Now I thought I could pass a lisp string as :simple-string
without it being stationary data, provided I didn't want it to use it
beyond the duration of the foreign function call, since I assumed that
garbage collection would not occur whilst the foreign function was being
executed. So, my question is, are my assumptions incorrect or is there
a bug in the Lucid foreign function interface?

If my assumptions are incorrect, does this mean that I have to use
with-static-area to allocate all strings that I pass to foreign functions ?
I'd rather not do this, because the strings I'm creating have no need to
be permanent.

All this refers to Lucid Common Lisp version 4.0, running on Sun SparcStations
under SunOS 4.1.3.

--
Chris Paine                   (···@ist.co.uk)
Imperial Software Technology, Cambridge, U.K.
"I'm happy, I'm happy, I'm happy ... and I'll punch the man who says I'm not."

From: Christopher Hoover
Subject: Re: Problem with string passing in Lucid CL Foreign Function Interface.
Date: 
Message-ID: <CnLM7p.90G.3@cs.cmu.edu>
In article <·····················@upper.ist.co.uk>,
Chris Paine <···@upper.ist.co.uk> wrote:
>I am calling a C function from Lisp using the Lucid foreign function
>interface. One of the arguments is a string, and I specify :simple-string
>as its type in the def-foreign-function form. The problem is that there
>seems to be window such that a garbage collection can result in the
>C function getting a pointer to rubbish because the garbage collector
>has moved the lisp string (at least I think that this is what is
>happening).

You're conclusion is probably correct.

>Now I thought I could pass a lisp string as :simple-string
>without it being stationary data, provided I didn't want it to use it
>beyond the duration of the foreign function call, since I assumed that
>garbage collection would not occur whilst the foreign function was being
>executed. So, my question is, are my assumptions incorrect or is there
>a bug in the Lucid foreign function interface?

You won't return to lisp-land iff:

1) You don't callback into lisp (LCL:DEF-FOREIGN-CALLBACK).

  This should be obvious.

2) You aren't using multiprocessing.

  The scheduler can kick in while you are in foreign code and switch
  you back into lisp land.  You can disable it around foreign calls if
  you want to avoid this particular problem.  You may find this
  necessary anyways if you are calling code that isn't signal safe.
  
3) Your foreign code doesn't call malloc(3).

  The malloc you see in LCL is not the malloc from libc.a.  Instead it
  is a specialized version that understands how to allocate blocks
  that can live in/around the lisp heap.  While many calls to it do
  not return to lisp land, is definitely possible for a call to
  return.  Furthermore when this happens it's also possible to GC.  If
  you malloc enough data it's almost inevitable.

  It is hard to avoid calling malloc completely since many libc
  functions do so indirectly.

>If my assumptions are incorrect, does this mean that I have to use
>with-static-area to allocate all strings that I pass to foreign functions ?
>I'd rather not do this, because the strings I'm creating have no need to
>be permanent.

You could do this, or you could use LCL:MALLOC-FOREIGN-POINTER and copy
the string into the returned space.  Here's a handy utility (from the LCL
manuals I think):

  (defun malloc-foreign-string (s)
    (check-type s string)
    (let* ((length (length s))
	   (foreign-string (lcl:malloc-foreign-pointer
			    :type `(:pointer
				    (:array :character (,(1+ length)))))))
      (setf (lcl:foreign-string-value foreign-string) s)
      (setf (lcl:foreign-pointer-type foreign-string) '(:pointer :character))
      foreign-string))

As always with malloc'ed storage, don't forget to free it when you no
longer need it.

I also have a WITH-FOREIGN-STRINGS macro that I use for the cases
where the lifetime of the foreign string has dynamic extent.  The
macro is useful in 90% of the foreign calls I deal with.  It's a big
win because it has the necessary UNWIND-PROTECT frobs and such to
prevent storage leaks.

Hope this helps.

-- Chris.
(··@lks.csi.com)
From: Christopher Hoover
Subject: Re: Problem with string passing in Lucid CL Foreign Function Interface.
Date: 
Message-ID: <CnLq8D.Bu2.3@cs.cmu.edu>
In article <············@cs.cmu.edu>,
Christopher Hoover <···@cs.cmu.edu> wrote:
>In article <·····················@upper.ist.co.uk>,
>Chris Paine <···@upper.ist.co.uk> wrote:
>>I am calling a C function from Lisp using the Lucid foreign function
>>interface. One of the arguments is a string, and I specify :simple-string
>>as its type in the def-foreign-function form. The problem is that there
>>seems to be window such that a garbage collection can result in the
>>C function getting a pointer to rubbish because the garbage collector
>>has moved the lisp string (at least I think that this is what is
>>happening).
>
>You're conclusion is probably correct.
s/You're/Your/

Sorry.  Sigh.  I should read what I type before I send it.

-- Chris.
(··@lks.csi.com)