Segfault in do_realize_lazy_struct

Issue #356 resolved
Peter Inglesby
created an issue

Background: I'm trying to use CFFI to allow SQLite extensions to be written in Python, and am currently at the playing-around stage. There is a repo with full code here.

I am able to build a .dylib that can be loaded as an extension by SQLite, and which defines a SQL function. However, when I call the function from SQLite, I get a segfault in CFFI's code when I try to access a member of the global sqlite3_api struct.

sqlite> .load test_plugin
Hello from C!
pApi 0x1098bf880
pApi->value_type 0x1098049c0
sqlite> select rot13("hi");
Hello from Python!
['rot13', 'sqlite3_api']
<cdata 'struct sqlite3_api_routines *' 0x1098bf880>
Segmentation fault: 11 (core dumped)

The segfault is in do_realize_lazy_struct, with ctf being unexpectedly NULL. (See lldb output below.)

I am on OSX, with Python 3.6.0 and cffi 1.11.4. Please let me know if there are other details I can provide.

(lldb) bt
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
* thread #1: tid = 0x0000, 0x000000011029a423 _cffi_backend.cpython-36m-darwin.so`do_realize_lazy_struct(ct=0x00000001101a8c18) + 611 at realize_c_type.c:747, stop reason = signal SIGSTOP
  * frame #0: 0x000000011029a423 _cffi_backend.cpython-36m-darwin.so`do_realize_lazy_struct(ct=0x00000001101a8c18) + 611 at realize_c_type.c:747
    frame #1: 0x00000001102b0781 _cffi_backend.cpython-36m-darwin.so`cdata_getattro(cd=0x0000000110197710, attr=0x0000000110265b70) + 129 at _cffi_backend.c:2706
    frame #2: 0x000000010fd8a5d1 test_plugin.dylib`_PyEval_EvalFrameDefault(f=<unavailable>, throwflag=<unavailable>) + 19649 at ceval.c:2815 [opt]
    frame #3: 0x000000010fd903c9 test_plugin.dylib`_PyEval_EvalCodeWithName [inlined] PyEval_EvalFrameEx(f=0x00007f8089c05498, throwflag=0) + 19 at ceval.c:718 [opt]
    frame #4: 0x000000010fd903b6 test_plugin.dylib`_PyEval_EvalCodeWithName(_co=<unavailable>, globals=<unavailable>, locals=<unavailable>, args=<unavailable>, argcount=<unavailable>, kwnames=0x0000000000000000, kwargs=<unavailable>, kwcount=0, kwstep=<unavailable>, defs=<unavailable>, defcount=<unavailable>, kwdefs=<unavailable>, closure=<unavailable>, name=<unavailable>, qualname=<unavailable>) + 3622 at ceval.c:4119 [opt]
    frame #5: 0x000000010fd858c4 test_plugin.dylib`PyEval_EvalCodeEx(_co=<unavailable>, globals=<unavailable>, locals=<unavailable>, args=<unavailable>, argcount=<unavailable>, kws=<unavailable>, kwcount=0, defs=0x0000000000000000, defcount=0, kwdefs=0x0000000000000000, closure=0x0000000000000000) + 100 at ceval.c:4140 [opt]
    frame #6: 0x000000010fce281d test_plugin.dylib`function_call(func=<unavailable>, arg=<unavailable>, kw=<unavailable>) + 381 at funcobject.c:604 [opt]
    frame #7: 0x000000010fcb9f45 test_plugin.dylib`PyObject_Call(func=0x0000000110054e18, args=0x0000000110266120, kwargs=0x0000000000000000) + 101 at abstract.c:2246 [opt]
    frame #8: 0x00000001102a3872 _cffi_backend.cpython-36m-darwin.so`general_invoke_callback(decode_args_from_libffi=0, result=0x00007fff5027efb0, args="@\x8c\x81\x8a\x80\x7f", userdata=0x000000011023e9f8) + 386 at _cffi_backend.c:5641
    frame #9: 0x00000001102b5332 _cffi_backend.cpython-36m-darwin.so`cffi_call_python(externpy=0x000000010fe6e5d8, args="@\x8c\x81\x8a\x80\x7f") + 146 at call_python.c:256
    frame #10: 0x000000010fcae653 test_plugin.dylib`rot13(a0=<unavailable>, a1=<unavailable>, a2=<unavailable>) + 51 at test_plugin.c:2131 [opt]
    frame #11: 0x000000010f9dbc9e sqlite3`sqlite3VdbeExec + 35294
    frame #12: 0x000000010f9a2e86 sqlite3`sqlite3Step + 518
    frame #13: 0x000000010f9a2aed sqlite3`sqlite3_step + 125
    frame #14: 0x000000010f99654d sqlite3`exec_prepared_stmt + 29
    frame #15: 0x000000010f98ab9b sqlite3`shell_exec + 1211
    frame #16: 0x000000010f997da2 sqlite3`runOneSqlLine + 146
    frame #17: 0x000000010f98d7ab sqlite3`process_input + 1147
    frame #18: 0x000000010f98231d sqlite3`main + 5565
    frame #19: 0x00007fff923e75ad libdyld.dylib`start + 1
(lldb) fr v 
(CTypeDescrObject *) ct = 0x00000001101a8c18
(builder_c_t *) builder = 0x000000010ffd48c8
(char *) p = 0x00007fff5027e8f0 "sqlite3_api_routines"
(int) n = 2
(int) i = 114
(int) sflags = 1
(const _cffi_struct_union_s *) s = 0x000000010fe6c6f0
(const _cffi_field_s *) fld = 0x000000010fe6b920
(PyObject *) fields = 0x000000011027cc48
(PyObject *) args = 0x000000010fd854ff
(PyObject *) res = 0x00007fff5027e9b0
(_cffi_opcode_t) op = 0x000000000002fa11
(int) fbitsize = -1
(PyObject *) f = 0x0000000110279c28
(CTypeDescrObject *) ctf = 0x0000000000000000

Comments (3)

  1. Armin Rigo

    Fixed in e8b85a3539f2, thanks! It crashed instead of giving an error---after the fix, we get the error clearly: the type va_list cannot be used in other members of this big struct as function argument, because it's a completely unknown type. Likely, the most portable solution is to comment out and never use the two functions that use va_list in their signature.

  2. Log in to comment