[Openmcl-devel] Question about foreign-functions

Gary Byers gb at clozure.com
Fri Nov 21 11:43:16 PST 2003

On Fri, 21 Nov 2003, Camille Troillard wrote:

> Hello OpenMCL,
> I am Camille, and I am new to this list.
> I am building a web server application with PortableAllegroServe with
> webaction and CL-SQL with OpenMCL on Mac OS X 10.3.
> I am getting some problems with FFI :  Here is a code sample that
> doesn't work.  It is very likely that I am wrong, because I just start
> writing Lisp programs.
> This function is supposed to call the function "stat", access the
> st_ino field of the structure  and return the result which is
> (supposedly) an int.
> (defun filesys-inode (path)
>    (let ((checked-path (probe-file path)))
>      (cond (checked-path
> 	   (rlet ((pstat (:* (:struct stat))))
> 		 (with-cstrs ((str (namestring checked-path)))
> 		   (#_stat str pstat))
> 		 (pref pstat :stat.st_ino)))
> 	  (t (error "path ~s does not exist" path)))))
> If I call this function I get this error :
>  > Error in process listener(1): value 0 is not of the expected type
>  > While executing: "Unknown"

RLET takes a sequence of variable name/foreign type pairs and executes
its body with each variable bound to a temporary (stack-allocated) pointer
to an instance of the corresponding foreign type.

When you say "(rlet ((pstat (:* (struct stat)))) ...)", you're basically
saying "let PSTAT be a pointer to a pointer to a STAT structure."  That's
a perfectly legal and meaningful thing to say, but it's not what you
mean here; all that's being allocated is an uninitialized "pointer to
a STAT structure", and PSTAT is then made to point at that uninitialized

To look at this another way:

  (rlet ((pstat :stat)) ...)

correctly allocates a :stat structure, which is 96 bytes wide on OSX,
and makes PSTAT point at that chunk of stack-allocated memory.

  (rlet ((pstat (:* (:struct :stat)))) ...)

incorrectly allocates a 4-byte pointer, and makes PSTAT point at the
4-byte chunk that was allocated to hold that pointer.

Passing a pointer to a 4-byte chunk of memory to a function (#_stat)
that expects to be able to write into a 96-byte chunk of memory overwrites
that 4-byte chunk and the next 92 bytes that happen to be nearby it on
the stack.   When your code returns to the read-eval-print loop, it
says something nonsensical; it's kind of amazing that it can say
anything at all, since there's probably about half of a :STAT structure
lodged in its stack frame ...

> If I put a "print" form around the pref call, the result I correctly
> printed on the standard output and then the error arises.  A look to
> the backtrace confirms that the error occurs outside of the
> "filesys-inode" call.

The values that #_stat wrote into what it thought was a pointer to
a :stat structure are certainly there.  (Some local variable values
in the next few stack frames just got overwritten.)

> If I replace rlet with rletz I get the following compilation error
> which I don't understand:
>  > Error in process listener(1): While compiling FILESYS-INODE :
>  >                               #1=(PSTAT (:* (:STRUCT STAT))) is not a
> symbol or lambda expression in the form (#1#) .
> I think that I must pass #_stat a reference to a stack allocated
> structure.
> The problem is that:
> 1.  I don't know how to pass a reference to a stack allocated object to
> #_stat
> 2.  I don't know how to declare a stat structure object because if I
> try :
> 	(rlet ((pstat (:struct stat)))

It should probably work to say that; RLET's not too consistent about
how it parses the foreign type specifier: it wants to give preference
to "record" (struct/union) names over type names (which aren't necessarily
equivalent), but doesn't handle some compound foreign type specs (like
(:struct ...)) correctly.  It'd be more consistent if it did, but you
can simply use the record name:

       (rlet ((pstat :stat)) ...)

and that's exactly what you want to do here.

> 		...
> I get a compilation error.
> Thanks in advance for any help!
> Kind Regards,
> Camille Troillard
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel

More information about the Openmcl-devel mailing list