undefined symbol: PyExc_SystemError with RTLD_LOCAL

Create issue
Issue #264 closed
Former user 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

    Works for me. I guess the issue is somehow specific to an exact OS or Linux distribution. Can you give details about that?

  2. 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.

  3. Armin Rigo

    And in fact, the same is true for ldd /usr/lib/python2.7/dist-packages/_cffi_backend.x86_64-linux-gnu.so.

  4. 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
    
  5. 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
    
  6. 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)
    
  7. Armin Rigo

    Ok: for some reason on my Arch Linux system the _cffi_backend.so ends up with an explicit dependency to libpython2.7.so.1.0, whereas yours does not.

  8. 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).

  9. 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)
    
  10. 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.)

  11. 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.

  12. Kevin Palm

    Hi guys, I wanted to share with you the information that I encountered the same problem, and that the solution provided by @gvaladon worked for me. (Thank you very much !)

  13. Log in to comment