After reading the Apple documentation for Executing Mach-O files it says:
The two-level namespace feature of OS X v10.1 and later adds the module name a
The symbols within libpython (e.g. libpython2.7.dylib) are being resolved correctly. For example, under the above described scenario, I see PyModule_GetDict()
get called 155 times before the incorrectly resolved call.
The problem is that python itself is compiling shared libraries, and it's using dlopen()
to load them. You can see the dlopen()
happening by setting the environment variable PYTHONVERBOSE
when running:
$ PYTHONVERBOSE=1 ./main 2>&1 | grep dlopen
which produces:
dlopen(".../lib/python2.7/lib-dynload/_locale.so", 2);
The 2
argument corresponds to RTL_NOW
, but that doesn't matter too much. The issue is that this separate library isn't able to indicate that it's symbols should be resolved against the libpython2.7.dylib library. Yet, it does have several python symbols; in particular, this one that ends up causing the problem:
$ nm prefix/lib/python2.7/lib-dynload/_locale.so | grep GetDict
U _PyModule_GetDict
So, when python dlopen()
s the library, all it can do is resolve the symbol without the qualification. Apparently, the semantic of the dl
functionality is to resolve such symbols based on the order the libraries are loaded, as you noted.
So, things work fine until we load _locale.so
, as you can see from the following backtrace:
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x50)
* frame #0: 0x00000001003f3fc1 libpython3.6m.dylib`PyErr_FormatV [inlined] PyErr_Restore at errors.c:42 [opt]
frame #1: 0x00000001003f3fb7 libpython3.6m.dylib`PyErr_FormatV [inlined] PyErr_Clear at errors.c:355 [opt]
frame #2: 0x00000001003f3fb7 libpython3.6m.dylib`PyErr_FormatV(exception=0x00000001004cba18, format="%s:%d: bad argument to internal function", vargs=0x00007fff5fbfdcb0) at errors.c:841 [opt]
frame #3: 0x00000001003f2c39 libpython3.6m.dylib`PyErr_Format(exception=<unavailable>, format=<unavailable>) at errors.c:860 [opt]
frame #4: 0x0000000100358220 libpython3.6m.dylib`PyModule_GetDict(m=0x0000000101a5a868) at moduleobject.c:450 [opt]
frame #5: 0x00000001000f491c _locale.so`init_locale at _localemodule.c:703 [opt]
frame #6: 0x00000001018d1176 libpython2.7.dylib`_PyImport_LoadDynamicModule(name="_locale", pathname=".../lib/python2.7/lib-dynload/_locale.so", fp=<unavailable>) at importdl.c:53 [opt]
Also worth noting, _locale.so
is just the first library to fail. If you got past it somehow, there are quite a few other libraries that potentially will have similar problems in .../lib/python2.7/lib-dynload
.