undefined symbol: PyExc_SystemError with RTLD_LOCAL

Issue #264 closed
Anonymous created an issue

I'm trying to dlopen() a shared library created by CFFI from demo/embedding.py example:

#!/usr/bin/env python

import cffi

ffi = cffi.FFI()

ffi.embedding_api("""
    int add(int, int);
""")

ffi.embedding_init_code("""
    from pyembedded import ffi
    print("preparing")   # printed once

    @ffi.def_extern()
    def add(x, y):
        print("adding %d and %d" % (x, y))
        return x + y
""")

ffi.set_source("pyembedded", "")

ffi.compile(verbose=True)
#include <stdio.h>
#include <dlfcn.h>

int
main(int argc, char *argv)
{
    void *py = dlopen("./pyembedded.so", RTLD_NOW | RTLD_LOCAL);
    if (py == NULL) {
        fprintf(stderr, "Failed to load library\n");
        return -1;
    }

    int (*add)(int, int) = dlsym(py, "add");
    if (add == NULL) {
        fprintf(stderr, "Failed to find 'add' function\n");
        dlclose(py);
        return -1;
    }

    int c = add(10, 15);

    printf("result: %d\n", c);

    dlclose(py);
    return 0;
}

gcc test.c -o test -ldl

roman@book:~$ ./test
ImportError: /usr/lib/python2.7/dist-packages/_cffi_backend.x86_64-linux-gnu.so: undefined symbol: PyExc_SystemError

From: pyembedded
compiled with cffi version: 1.6.0
_cffi_backend module: not loaded
sys.path: ['/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/home/roman/.local/lib/python2.7/site-packages', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7']

function add() called, but initialization code failed.  Returning 0.
result: 0

RTLD_LOCAL works properly.

Comments (16)

  1. Armin Rigo

    Can you paste ldd ./pyembedded.so? It should normally contain a line about libpython2.7.so. If it doesn't, then maybe you can get the error message that you got.

  2. Guillaume Valadon

    Same issue here (Ubuntu/xenial & cffi 1.10.0 from pip). Let me know if you need more information.

    python test.py
    gcc -o test test.c -ldl
    ./test
    ImportError: /home/ubuntu/ve_cffi/local/lib/python2.7/site-packages/_cffi_backend.so: undefined symbol: PyExc_SystemError
    
    From: pyembedded
    compiled with cffi version: 1.10.0
    _cffi_backend module: not loaded
    sys.path: ['/home/ubuntu/ve_cffi/lib/python2.7', '/home/ubuntu/ve_cffi/lib/python2.7/plat-x86_64-linux-gnu', '/home/ubuntu/ve_cffi/lib/python2.7/lib-tk', '/home/ubuntu/ve_cffi/lib/python2.7/lib-old', '/home/ubuntu/ve_cffi/lib/python2.7/lib-dynload', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/home/ubuntu/ve_cffi/local/lib/python2.7/site-packages', '/home/ubuntu/ve_cffi/lib/python2.7/site-packages']
    
    function pyembedded.add() called, but initialization code failed.  Returning 0.
    result: 0
    
  3. Armin Rigo

    I'm waiting for more information as asked above. Repeating:

    ldd ./pyembedded.so
    ldd /home/ubuntu/ve_cffi/local/lib/python2.7/site-packages/_cffi_backend.so
    
  4. Guillaume Valadon

    Here are the outputs. Hope this helps.

     ldd ./pyembedded.so
        linux-vdso.so.1 =>  (0x00007ffeaddb2000)
        libpython2.7.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 (0x00007f5adf803000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5adf5e6000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5adf21b000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f5adf001000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5adedfd000)
        libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f5adebf9000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5ade8f0000)
        /lib64/ld-linux-x86-64.so.2 (0x000055cb3bea5000)
    
    ldd /home/ubuntu/ve_cffi/local/lib/python2.7/site-packages/_cffi_backend.so
        linux-vdso.so.1 =>  (0x00007ffd2894b000)
        libffi-72499c49.so.6.0.4 => /home/ubuntu/ve_cffi/local/lib/python2.7/site-packages/.libs_cffi_backend/libffi-72499c49.so.6.0.4 (0x00007fd9eda7d000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd9ed859000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd9ed48f000)
        /lib64/ld-linux-x86-64.so.2 (0x000055ef314ce000)
    
  5. Armin Rigo

    The problem seems really to be that sometimes, _cffi_backend.so is created without the dependency to libpython2.7.so.1.0. I have not been able to understand why so far. I could reproduce it on a custom-compiled Python 3.5.3, but the same custom-compiled Python 3.5.3 also contains its own extension modules like cmath.cpython-35m-x86_64-linux-gnu.so and these ones do have the dependency.

    The problem appears to show up only if the dependency is missing and we are in the middle of a dlopen(..., RTLD_LOCAL).

  6. Guillaume Valadon

    Could it be related to "Debian Python does not link extensions to libpython (as is done in some operating systems). Symbols are resolved by /usr/bin/pythonX.Y which is not linked to libpython." (https://www.debian.org/doc/packaging-manuals/python-policy/ch-module_packages.html) ?

    Compiling from source gives me:

    debian$ ldd build/lib.linux-x86_64-2.7/_cffi_backend.so     linux-vdso.so.1 (0x00007ffc748d5000)
        libffi.so.6 => /usr/lib/x86_64-linux-gnu/libffi.so.6 (0x00007f606c110000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f606bef3000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f606bb54000)
        /lib64/ld-linux-x86-64.so.2 (0x00005595fbd96000)
    
    arch$ ldd build/lib.linux-x86_64-2.7/_cffi_backend.so
        linux-vdso.so.1 (0x00007ffec81e5000)
        libffi.so.6 => /usr/lib/libffi.so.6 (0x00007f3e17413000)
        libpython2.7.so.1.0 => /usr/lib/libpython2.7.so.1.0 (0x00007f3e17029000)
        libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f3e16e0b000)
        libc.so.6 => /usr/lib/libc.so.6 (0x00007f3e16a67000)
        /usr/lib64/ld-linux-x86-64.so.2 (0x000055b51e13d000)
        libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f3e16863000)
        libutil.so.1 => /usr/lib/libutil.so.1 (0x00007f3e16660000)
        libm.so.6 => /usr/lib/libm.so.6 (0x00007f3e1634b000)
    
  7. Armin Rigo

    I have no clue how to work around this problem. Maybe there is no nicer solution than using dlopen(..., RTLD_GLOBAL) in the first place. I'm not sure I understand what RTLD_LOCAL does very exactly, but it seems that if you are within the recursion from a dlopen(..., RTLD_LOCAL), then libpythonX.Y.so will fail to import any extension module that doesn't explicitly link to libpythonX.Y.so again. If I'm correct, then there is very little I can do. (I can mention the issue in the documentation.)

  8. Armin Rigo

    Ah, so that means that libpython2.7.so is first loaded globally, after which pyembedded.so can be loaded locally? If that works, then yes, it looks like a good solution to mention in the documentation.

  9. Log in to comment