[Openmcl-devel] RDNZL in CCL: Exception occurred while executing foreign code

Gary Byers gb at clozure.com
Fri Oct 16 21:54:38 PDT 2009


R. Matthew Emerson wrote:
>
> On Oct 16, 2009, at 5:28 PM, John Miller wrote:
>
>> The problem looks to be one of passing the wrong type of argument. 
>>  The C function I am calling is defined as 
>>
>> void* invokeInstanceMember(const __wchar_t *methodName, void *target, 
>> int nargs, void *args[])
>>
>> h-to-ffi.sh interprets that to be
>>
>> (function ("/cygdrive/d/rdnzl-cpp-0.7.1/RDNZL/ffi-headers.h" 55)
>>  "invokeInstanceMember"
>>  (function
>>   ((pointer (unsigned-short ())) (pointer (void ())) (int ()) 
>> (pointer (pointer (void ()))) )
>>   (pointer (void ()))) (extern))
>>
>> Then, given the following definitions:
>>
>> (defun %invoke-instance-member (method-name type nargs args)
>>   (ccl::with-native-utf-16-cstr (mn method-name)
>>     (#_invokeInstanceMember mn type nargs args)))
>>
>> (defun test-invoke-2 ()
>>   (let ((obj (make-type-from-name "System.Reflection.Assembly")))
>>     (%invoke-instance-member "ToString" (pointer obj) 0 
>> (ccl:%null-ptr))))
>>
>> (defun test-invoke-3 ()
>>   (let ((obj (make-type-from-name "System.Reflection.Assembly"))
>> (type (box* "System.Reflection.Assembly")))
>>     (ccl:rletz ((ptr (:array :address 1)))
>>       (setf (ccl:paref ptr (:array :address) 0) type)
>>       (%invoke-instance-member "GetType" (pointer obj) 1 ptr))))
>>
>> I call (test-invoke-2) and all is hunky-dorey, but I try 
>> (test-invoke-3) and all heck breaks loose.  I have imagined, and 
>> tried a couple different ways of representing an array of pointers, 
>> but clearly I am not imaginative enough.
>>
>> It would be interesting to know if anyone else has tried calling 
>> foreign functions that have arguments of type void *args[].  I mean 
>> other than the code in cocoa-ide/start.lisp that I based the code in 
>> test-invoke-3 off of.
>
> It seems to me that you're stack-allocating the array of pointers 
> correctly.
Agreed.  That makes me wonder what BOX* does, whether it's doing it 
right, and whether it's the right thing to do here.  I assume that we're 
trying to call the second method listed at:

<http://msdn.microsoft.com/en-us/library/system.reflection.assembly.gettype.aspx>

- the one that takes a String argument - and that BOX* of a lisp string 
returns a pointer to a .NET String.  Is this assumption correct, and if 
so, are we sure that it works (e.g., can we do something like return a 
lisp string from that .NET String, or otherwise test that) ?  This might 
turn out to be a dead end, but if we believe that we're passing the 
array of pointers correctly one of the next things to look at would seem 
to be the contents of that array ...


>
> I would try running the lisp under gdb.  Load the shared library that 
> contains 
> #_invokeInstanceMember, and then set a gdb breakpoint on it.  Then 
> evaluate (test-invoke-3), and see if the arguments provided from lisp 
> look right.
>
> Here's a trivial example I just came up with and ran on my Mac. (I 
> tried to do it on Windows, but I couldn't figure out at a quick glance 
> how to build a working dll with cygwin tools.)
[...]

I'm fairly sure that the library that John's trying to call into is 
written in "Managed C++"; if so, tools like GDB may have trouble making 
sense out any symbolic information that's available (MS compilers 
generate debugging info that's in an undocumented proprietary format).  
I don't know for sure; GDB might be able to at least find 
#_invokeInstanceMember, but things might get weird quickly.  (Weirder 
than usual, I mean.)



>
> #include <stdio.h>
>
> void testing(char *name, void *target, int nargs, void *args[])
> {
>   int i;
>
>   fprintf(stderr, "name = %s\n", name);
>   fprintf(stderr, "target = %p\n", target);
>   fprintf(stderr, "nargs = %d\n", nargs);
>
>   for (i = 0; i < nargs; i++)
>     fprintf(stderr, "args[%d] = %p\n", i, args[i]);
> }
>
> Compile that as a shared library, e.g., with cc -arch x86_64 -shared 
> ffi.c -o ffi.dylib or whatever the right thing is for your system. 
>  Sorry to hand-wave like this.
>
> With that in hand:
>
> ? (open-shared-library "ffi.dylib")
> #<SHLIB ffi.dylib #x300041594C2D>
>
> Now:
>
> (defun testing ()
>   (rlet ((args (:array :address 3)))
>     (setf (paref args (:array :address) 0) (%int-to-ptr 9)
>  (paref args (:array :address) 1) (%int-to-ptr 99)
>  (paref args (:array :address) 2) (%int-to-ptr 999))
>     (with-cstrs ((s "hello"))
>       (external-call "testing" :address s :address (%null-ptr) :int 3 
>     :address args :void))))
>
> ? (testing)
> name = hello
> target = 0x0
> nargs = 3
> args[0] = 0x9
> args[1] = 0x63
> args[2] = 0x3e7
>
> I don't know if that helps or not.
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel
>   

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.clozure.com/pipermail/openmcl-devel/attachments/20091016/94fe8511/attachment.htm>


More information about the Openmcl-devel mailing list