proper way to detect NULL char* on imported function?

Started by TedWalther, May 07, 2015, 03:14:07 PM

Previous topic - Next topic

TedWalther

I am importing a function from someones library that has this use pattern:



char* foo(int index, int* retval);


This function returns two things; the char* points to a string/label, and the integer retval is the value associated with it.  The int index indexes you into the table.



You are intended to iterate over the table from 0 on up, and stop when it returns the NULL pointer.



I beat my head on this for an hour, I was doing:



(import MY_LIB "foo" "char*" "int" "void*")


My code worked beautifully, but would segfault when it came to the NULL pointer.



I tried various things to detect when (foo) was returning a NULL pointer.  I tried (get-long (address)), I tried (address), I tried (get-long), I tried (get-long (get-long)), etc.



Finally I switched the import statement to void* instead of char*



(import MY_LIB "foo" "void*" "int" "void*")


Now I could detect NULL easily.



So, I'm using void* for now, but it would be nice to go back to using char*, char* works when I do regular (not extended) import of function foo, and the char* integration with native newlisp strings is really nice, not having to do the extra get-string step, especially because I'm dealing with a library that brings in binary data, and the strings are not terminated ones.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.

TedWalther

#1
After a bit more testing, I can reduce it to this: if an extended libffi imported function has a return type of char*, and it returns NULL when it is called, newlisp segfaults.



Perhaps the least surprising response to this is to return a "nil", since "char*" does map to a newlisp string type.



I verified that (get-string NULL) also segfaults, but perhaps this is the correct behavior.  It is conceivable that memory permissions could be set such that you could legitimately try to grab the byte at memory location 0.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.

Lutz

#2
I rather would like to leave things as they are as there are to many implications for other parts of the code like structure packing and unpacking.



If a NULL pointer can be expected as a return value use void* instead as a return type and do the conversion of a valid non zero returned string pointer using get-string.



In the same fashion when NULL is expected to be passed for a char* parameter use void* as parameter type instead.



void*  as parameter type, already takes newLISP strings besides numbers and automatically converts them to addresses and this is mentioned already in the docs.



I will add something to the documentation to make all this clearer.



ps: I could add an error message when a libffi char* return type function returns NULL.

TedWalther

#3
Lutz... anytime you deal with pointers, no matter what type, NULL can come up, and not necessarily be an error.  It is the standard "end of list" marker.  Even with documentation and an error code instead of a segfault, this is still very surprising behavior.



Can we do a conference offline by phone so you can fill me in more on the things that would be affected by making (import char*) return nil instead of an error, for NULL?  I propose the phone conference because I communicate and process information much more rapidly by voice, and language barrier will not be an issue for us.  I promise.



I'd like to get a better feel for how I can assist; I've been requesting a lot lately, and I'd like to become more of a bug-fixer and contributor, rather than bug-reporter and requestor.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.

Lutz

#4
If you expect 0 then either use void* and check for 0/NULL before calling get-string or if using char* use catch. I don't want to start a nil/NULL confusion. Also, when using libffi, nil is already used as return value for void return.