On 22 November 2017 at 21:59, Ben Coman <btc@openinworld.com> wrote:
On 22 November 2017 at 13:38, Todd Blanchard <tblanchard@mac.com> wrote:
I've been trying to track this down for a couple weeks now.
I have concluded that structs passed by value to functions on the 64 bit VM are not properly populated. The struct's memory is all zero'd.
I found this while trying to work with LibClang and found that functions that fetched code locations from code ranges always returned invalid zero'd locations. After spending some time with lldb I have traced the problem into the native code and found that the argument is not correct.
I've carved out the wee bit of clang to reproduce this in a tiny library.
The gist of it is below and the entire file is included. Basically the struct passed to the function clang_getRangeStart is zero'd memory regardless of the data I send from the image side.
The build command I used on sierra is clang -shared -undefined dynamic_lookup -o microclang.dylib microclang.c
On Ubuntu 16.04 I used... $ clang -shared -fPIC -o libmicroclang.so microclang.c
$ clang test.c -L. -l microclang test.c:6:53: error: no member named 'begin_int_data' in 'CXSourceLocation' if(clang_getRangeStart(clang_getArbitraryRange()).begin_int_data == 0)
I presume you meant... if(clang_getRangeStart(clang_getArbitraryRange()).int_data == 0) so correcting and continuing...
$ clang test.c -L. -l microclang $ LD_LIBRARY_PATH=. ./a.out That failed
So I'm not sure how to proceed. I was expecting that would work while Pharo failed.
Now interestingly... $ clang test.c microlang.c $ ./a.out That worked
So it seems a similar problem exists outside our FFI.
cheers -ben
P.S. I refactored you code to extract a header file (attached)
The issue is still beyond my ken, but I've made some progress towards isolating/understanding the issue. Attached zip exploded here for easy reference... ___microlang.h___ typedef unsigned uintptr_t; typedef struct { const void *ptr_data[2]; } CXSourceRange_; CXSourceRange_ clang_getArbitraryRange_(); int clang_getRangeEnd_(CXSourceRange_ range); ___microclang.c___ #include "microclang.h" const char* libraryString = "library_pointer"; CXSourceRange_ clang_getArbitraryRange_() { CXSourceRange_ range = {0}; range.ptr_data[0] = (void*)libraryString; return range; } int clang_getRangeEnd_(CXSourceRange_ range) { // Special decoding for CXSourceLocations for CXLoadedDiagnostics. if ((uintptr_t)range.ptr_data[0] & 0x1) { return 0; } else { return 1; } } ___test.c___ #include <stdio.h> #include "microclang.h" const char* localString = "local_pointer"; void test( CXSourceRange_ range, char *note ) { int result = clang_getRangeEnd_(range); if(result == 0) { printf("That failed (%s)\n", note); } else { printf("That worked (%s)\n", note); } } int main() { CXSourceRange_ range1 = clang_getArbitraryRange_(); test(range1, "library string"); CXSourceRange_ range2 = {0}; range2.ptr_data[0] = (void*)localString; test(range2, "local string"); } ___Makefile___ default: clean static shared clean: rm -f *so *App @echo shared: clang -g -o libmicroclang.so -shared -fPIC microclang.c clang -g -o sharedApp test.c -L. -lmicroclang LD_LIBRARY_PATH=. ./sharedApp @echo static: clang -g -o staticApp test.c microclang.c ./staticApp @echo Now running... $ make > report gives... ___report___ rm -f *so *App clang -g -o staticApp test.c microclang.c ./staticApp That worked (library string) That worked (local string) clang -g -o libmicroclang.so -shared -fPIC microclang.c clang -g -o sharedApp test.c -L. -lmicroclang LD_LIBRARY_PATH=. ./sharedApp That failed (library string) That worked (local string) cheers -ben