jeudi 3 septembre 2015

Segfault in Cython callback

I'm currently a bit stuck and was hoping for some guidance. I've got a small module that wraps sqlite and I want to allow user-defined Python functions to be executed using a hook provided by sqlite.

Here is the definition from the SQLite header file:

cdef extern from "sqlite3.h":
    cdef void *sqlite3_commit_hook(sqlite3*, int(*xFunc)(void*), void*)

Here is the corresponding Cython:

# Reference to user-provided function.
cdef object py_commit_hook = None

# Typedef for callback
ctypedef int(*commit_callback)(void *data)

# Wrapper function that will in turn call the user-provided python callback.
cdef int commit_hook_wrapper(void *data):
    print 'hello'  # Just for debugging.
    py_commit_hook()

# API used to set callback and make sqlite3 library call.
def set_commit_hook(DatabaseHelper db, callback):
    cdef commit_callback f
    global py_commit_hook

    py_commit_hook = callback
    f = commit_hook_wrapper

    sqlite3_commit_hook(db.db, f, <void *>0)

Using gdb, here is the traceback:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b16e2d in PySys_GetObject () from /usr/lib/libpython2.7.so.1.0
(gdb) bt
#0  0x00007ffff7b16e2d in PySys_GetObject () from /usr/lib/libpython2.7.so.1.0
#1  0x00007ffff567d291 in __Pyx_GetStdout () at pysqlite_ext.c:6121
#2  __Pyx_PrintOne (f=0x0, o=0x7ffff7e39270) at pysqlite_ext.c:6227
#3  __pyx_f_12pysqlite_ext_commit_hook_wrapper (__pyx_v_data=<optimized out>)
    at pysqlite_ext.c:2526
#4  0x00007ffff58ffb36 in ?? () from /usr/lib/libsqlite3.so.0
#5  0x00007ffff590ac5e in ?? () from /usr/lib/libsqlite3.so.0
#6  0x00007ffff590bd4f in sqlite3_step () from /usr/lib/libsqlite3.so.0
#7  0x00007ffff5b6ffb0 in pysqlite_step ()
   from /usr/lib/python2.7/lib-dynload/_sqlite3.so

It appears to be failing at the print call in the commit_hook_wrapper function:

(gdb) f 1
#1  0x00007ffff567d291 in __Pyx_GetStdout () at pysqlite_ext.c:6121
6121        PyObject *f = PySys_GetObject((char *)"stdout");
(gdb) l
6116        }
6117    }
6118    
6119    #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION < 3
6120    static PyObject *__Pyx_GetStdout(void) {
6121        PyObject *f = PySys_GetObject((char *)"stdout");
6122        if (!f) {
6123            PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout");
6124        }
6125        return f;

I'm completely stumped! Any ideas what might be going wrong?

I am dynamically linking to libsqlite3, and I wonder if this might be the issue. I've implemented callbacks before along these lines and never had issues, however this time it seems to fail no matter what I try.

Aucun commentaire:

Enregistrer un commentaire