Dec
23
2009

Hitting the dynamic linker wall…

I was working on replacing some mockup code for testing an internal library with python. Basically, the C code is incredibly big and I would rather mock the 3rd party API we are using in python. I wrote a generator to create wrapping code that forwards the C API calls to my python module.

Now that most of the work is finished, I get the following error message from my python mock:

1
2
3
4
5
6
Traceback (most recent call last):
  File "simple_mockup.py", line 2, in <module>
    import threading
  File "/usr/lib/python2.5/threading.py", line 11, in <module>
    from time import time as _time, sleep as _sleep
ImportError: /usr/lib/python2.5/lib-dynload/time.so: undefined symbol: PyExc_ValueError

What’s going on here? This issue reminds me of a bug of my ancient Debian times which affected loading of GTK theme engines from python-gtk. The bug (#38138) is so old, it’s not even in the BTS archive anymore…

The problem is illustrated by the following example program (consisting of three files):

demo.c
1
2
3
4
5
6
7
#include <Python.h>

void test_python()
{
    Py_Initialize();
    PyRun_SimpleString("import threading\n");
}
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <dlfcn.h>

int main(void)
{
    const char *error;

    void *handle = dlopen("./demo.so", RTLD_LAZY | EXTRA_RTLD_FLAGS);
    void (*test_python)();
    *(void**) &test_python = dlsym(handle, "test_python");
    if ((error = dlerror())) {
        fprintf(stderr, "%s\n", error);
        return 1;
    }

    printf("Calling test_python @ %p in shared object @ %p.\n", test_python, handle);
    (*test_python)();
    dlclose(handle);
    printf("Feels fine, finishing.\n");
    return 0;
}
run_it.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
#! /bin/sh

gcc -shared `python-config --includes` -o demo.so demo.c `python-config --ldflags`

echo "Running example with default RTLD flags:"
gcc -DEXTRA_RTLD_FLAGS=0 -o main main.c -ldl
./main
echo

echo "Passing RTLD_GLOBAL in addition:"
gcc -DEXTRA_RTLD_FLAGS=RTLD_GLOBAL -o main main.c -ldl
./main
echo

On my system, this results in the following output:

torsten@pulsar:~/sh_bug$ ./run_it.sh
Running example with default RTLD flags:
Calling test_python @ 0xb77084bc in shared object @ 0x96bc018.
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib/python2.5/threading.py", line 11, in 
    from time import time as _time, sleep as _sleep
ImportError: /usr/lib/python2.5/lib-dynload/time.so: undefined symbol: PyExc_ValueError
Feels fine, finishing.

Passing RTLD_GLOBAL in addition:
Calling test_python @ 0xb783f4bc in shared object @ 0x95e1018.
Feels fine, finishing.

Sucky. So embedding Python into an application is easy but if you want to use the interpreter and its modules from a plugin, you are out of luck. Somebody knows a way around this problem? The only solution I can think of is to link libpython.so into each of the python plugins.

Update: Work around

Small update: For my current problem, the work around is to run the application with the python library preloaded: LD_PRELOAD=/usr/lib/libpython2.5.so.1.0 app. Back to adding functionality…

tags: , ,
posted in Python by admin

Follow comments via the RSS Feed | Leave a comment | Trackback URL

Leave Your Comment

You must be logged in to post a comment.

 
Powered by Wordpress and MySQL. Theme by openark.org