-
Notifications
You must be signed in to change notification settings - Fork 61
The the C-API function PyEval_EvalFrameEx() is broken #166
Comments
Interesting, this must have been the case for years and years. |
Is it possible to have PyFrameObject compatible between stackless and non-stackless? |
The C-API functions PyEval_EvalFrameEx() and PyEval_EvalFrame() were broken, because Stackless does not use them and didn't test them. This commit adds test code and makes the functions compatible with C-Python. It is now save to call them from extension modules, i.e. modules created by Cython.
Nice! Haven't tested it, but thanks for doing this! It's certainly good for Stackless to have this fixed, but note that we can also disable the usage in Cython. We use several compatibility switches that enable or disable certain alternative implementations in other runtimes, which usually means PyPy. In this case, we could automatically disable the |
For sure it is possible to detect Stackless at compile time and at run time. The compile time check is simple: Traditionally Stackless tries to be strictly ABI compatible with C-Python. That is, a extension module compiled on C-Python runs on Stackless Python. If we want to preserve this level of compatibility, Cython must detect Stackless at runtime. Then Cython could either disable CYTHON_FAST_PYCALL or use the Stackless layout of PyFrameObject. If Cython uses PyFrameNew() and then only fills the f_localsplus array, a runtime switch is cheap. Pseudo code:
Without such a runtime switch, Cython code would crash in interesting ways. In the probably most common case (compiled with C-Python, running on Stackless, i.e. installed from a binary wheel), C-Python f_localsplus has the same offset as Stackless f_code. Filling the f_localsplus array overwrites f_code. I could add a test to PyEval_EvalFrameEx if f_code is really a code object and raise SystemError in case. Probably, we should discuss details in the Cython issue tracker. |
Support using PyEval_EvalFrameEx() without a main tasklet. And fix a potential reference counting problem.
The recent discussion in #165 showed, that commit d377c06 is not sufficient. Therefore I extended |
@kristjanvalur Your question "Is it possible to have PyFrameObject compatible between stackless and non-stackless?" still needs an answer. Stackless needs an additional member ( |
The C-API functions PyEval_EvalFrameEx() and PyEval_EvalFrame() were broken, because Stackless does not use them and didn't test them. This commit adds test code and makes the functions compatible with C-Python. It is now save to call them from extension modules, i.e. modules created by Cython. (cherry picked from commit d377c06)
Support using PyEval_EvalFrameEx() without a main tasklet. And fix a potential reference counting problem. (cherry picked from commit 187184b)
The C-API functions PyEval_EvalFrameEx() and PyEval_EvalFrame() were broken, because Stackless does not use them and didn't test them. This commit adds test code and makes the functions compatible with C-Python. It is now save to call them from extension modules, i.e. modules created by Cython. (cherry picked from commit d377c06)
Support using PyEval_EvalFrameEx() without a main tasklet. And fix a potential reference counting problem. (cherry picked from commit 187184b)
The C-API functions PyEval_EvalFrameEx() and PyEval_EvalFrame() were broken, because Stackless does not use them and didn't test them. This commit adds test code and makes the functions compatible with C-Python. It is now save to call them from extension modules, i.e. modules created by Cython. (cherry picked from commit d377c06)
Support using PyEval_EvalFrameEx() without a main tasklet. And fix a potential reference counting problem. (cherry picked from commit 187184b)
The C-API function PyEval_EvalFrameEx() is completely broken. Thanks to Kevin, who opened #165, I became aware of this problem.
Stackless does not use PyEval_EvalFrameEx(PyFrameObject *f, int throwflag). In theory an extension module can't use this function either, because the documented API provides no way to construct a PyFrameObject. Therefore Stackless did not test PyEval_EvalFrameEx() and untested code becomes buggy.
Nowadays Cython uses PyEval_EvalFrameEx to speed up calling Python functions. Cython uses the undocumented function PyFrame_New() to create a PyFrameObject (a struct) and then Cython fills the struct. Unfortunately the definitions of PyFrameObject differ between Stackless-Python and C-Python. Therefore you need to compile Cython code using Stackless-Python, if you want to run it with Stackless-Python.
The main problem of the current implementation of PyEval_EvalFrameEx is that it exposes Stackless features (i.e. stack unwinding) to an extension module, that is not prepared to handle this situation. Therefore I had to rewrite PyEval_EvalFrameEx.
The text was updated successfully, but these errors were encountered: