Hello,

With the following code:

test.pyx
--------
cdef extern from "foo.h":
    void foo() nogil except +

def bar():
    with nogil:
        foo()

foo.c
-----
void foo()
{
  throw std::runtime_error("foo exception");
}

The following crashes:
  python -c "import test; test.bar()"


Dumping at the code of bar() generated by Cython:

  { PyThreadState *_save;
    Py_UNBLOCK_THREADS
    /*try:*/ {
      try {foo();} catch(...) {__Pyx_CppExn2PyErr(); {__pyx_filename = 
__pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L6;}}
    }
    /*finally:*/ {
      int __pyx_why;
      __pyx_why = 0; goto __pyx_L7;
      __pyx_L6: __pyx_why = 4; goto __pyx_L7;
      __pyx_L7:;
      Py_BLOCK_THREADS
      switch (__pyx_why) {
        case 4: goto __pyx_L1_error;
      }
    }
  }

The problem is that __Pyx_CppExn2PyErr() accesses Python without the GIL.

There are several ways of fixing this.

1/ The simplest, but not the most optimized one: acquire/release the GIL within 
__Pyx_CppExn2PyErr().

2/ acquire/release the GIL in the catch clause only when "with nogil":
      try {foo();} catch(...) {PyGILState_STATE state = PyGILState_Ensure(); 
__Pyx_CppExn2PyErr(); PyGILState_Release(state); {__pyx_filename = __pyx_f[0]; 
__pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L6;}}

3/ restore the thread in the catch clause:
      try {foo();} catch(...) { Py_BLOCK_THREADS __Pyx_CppExn2PyErr(); 
{__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto 
__pyx_L6;}}
    }
    /*finally:*/ {
      int __pyx_why;
      Py_BLOCK_THREADS  // <<<<<<<<<<<<<<<<
      __pyx_why = 0; goto __pyx_L7;
      __pyx_L6: __pyx_why = 4; goto __pyx_L7;
      __pyx_L7:;
      switch (__pyx_why) {
        case 4: goto __pyx_L1_error;
      }
    }
  }

Cheers,
Stephane
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev

Reply via email to