Note that there are some explanatory texts on larger screens.

plurals
  1. POPropagating exceptions through dlsym cython
    primarykey
    data
    text
    <p>I am unable to propagate exceptions through dlsym. I use dlsym to load a cythonized python file. I made a minimal working example below so you can try it yourself:</p> <p>I have a pyx file, c_fun.pyx, which I compile to a C file using Cython. Then I'm using dlsym to load in the so file in another program, say use_fun.c++. You can use ./compile.sh to compile the files. On executing ./test, the program crashes with a segmentation fault.</p> <pre><code>#c_fun.pyx: cdef public double _myfunction(double x) except*: a=1/0 # This does not propagate an exception. Comment to make the example work return x**2-x # This works. #use_fun.c++ #include &lt;dlfcn.h&gt; #include &lt;stdio.h&gt; int main(int argc, char **argv) { void* handle = dlopen("./c_fun.so", RTLD_NOW | RTLD_GLOBAL); if(handle==NULL) { printf("%s \nat line number: %i\n",dlerror(),__LINE__); return; } double (*f)(double) = (double (*)(double))dlsym(handle, "_myfunction"); if(f==NULL) { printf("%s\n",dlerror()); return; } double res = 0; try { res = (*f)((double)99); } catch(char *err) { printf("Got exception: %s.\n", err); } printf("res = %f\n", res); } #setup.py from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext ext_modules = [Extension("c_fun", ["c_fun.pyx"], libraries = ['python2.7'], extra_compile_args= ['-fexceptions'])] setup( name = 'Hello world app', cmdclass = {'build_ext': build_ext}, ext_modules = ext_modules ) # compile.sh python setup.py build_ext --inplace echo "gcc use_fun.c++ -g -O0 -o test -ldl" g++ use_fun.c++ -g -O0 -o test -ldl </code></pre> <p>Initially, I tried without the "except*" at the end of my function, and without the "-fexceptions" compiler flag. But adding those do not change the behavior. gdb doesn't even allow me to backtrace the problem, and says: "Cannot find new threads: generic error ". I have looked on the internet for exception handling in combination with dlsym, but have found little information.</p> <p>The rest of the story: To make it more complicated, actually this use_fun.c++ file is a Python module which I imported. So: I'm using Python to load in a the module use_fun, and in that C++ module, _myfunction is called. But also then, I cannot get the exception handling right. However, in that case, I did successfully use gdb to get into the C code and see that PyErr_Format was successfully called. But the error is not triggered nor caught in the C++ code.</p> <p>Note that to be able to expose the file _myfunction, I have specified the 'public' keyword in the pyx file. Without it, the name mangling would cause the dlsym function call to fail. I tried looking for documentation on these two links: </p> <p><a href="http://docs.cython.org/src/userguide/external_C_code.html#using-cython-declarations-from-c" rel="nofollow">http://docs.cython.org/src/userguide/external_C_code.html#using-cython-declarations-from-c</a></p> <p><a href="http://docs.cython.org/src/userguide/language_basics.html#error-return-values" rel="nofollow">http://docs.cython.org/src/userguide/language_basics.html#error-return-values</a></p> <p>Edit: I have found the solution. I'll keep the original question above so it can help others. There were essentially 2 problems</p> <p>1) Of course, since C does not have exceptions, it was wrong to set a try/catch over the function! What does work, is checking whether an error occurred in Python using PyErr_Occurred().</p> <p>2) Since cython generates a module, it has to be initialized before you can properly use it. This means: calling Py_Initialize/Py_Finalize, and also calling the init_cfun method.</p> <p>The solution is shown below:</p> <pre><code>#include "Python.h" #include &lt;dlfcn.h&gt; #include &lt;stdio.h&gt; int main(int argc, char **argv) { Py_Initialize(); void* handle = dlopen("./c_fun.so", RTLD_NOW | RTLD_GLOBAL); if(handle==NULL) { printf("%s \nat line number: %i\n",dlerror(),__LINE__); return -1; } void (*init_func)(); *(void**)(&amp;init_func) = dlsym(handle, "initc_fun"); init_func(); double (*f)(double) = (double (*)(double))dlsym(handle, "_myfunction"); if(f==NULL) { printf("%s\n",dlerror()); return -1; } double res = 0; res = (*f)((double)99); if(PyErr_Occurred()) { PyErr_Print(); } printf("res = %f\n", res); Py_Finalize(); return 0; } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload