diff options
author | Stefan Behnel <stefan_ml@behnel.de> | 2020-04-11 19:16:55 +0200 |
---|---|---|
committer | Stefan Behnel <stefan_ml@behnel.de> | 2020-04-13 07:57:36 +0200 |
commit | b3c2e0d6791378a7361a1cc731ff93728b6a3d16 (patch) | |
tree | 5cb4b9dfe32f4ae6ecfe2f0e17270c994bcf1253 | |
parent | acd3fdcb93261d3ce245b6359c6b1684f6ac2782 (diff) | |
download | cython-b3c2e0d6791378a7361a1cc731ff93728b6a3d16.tar.gz |
Prevent calling PyObject_GC_Track() in __Pyx_CyFunction_New() when instantiating a fused function before the object fields of the fused function subtype are fully initialised.
See https://bugs.python.org/issue38392
Closes GH-3215.
Supersedes GH-3216.
-rw-r--r-- | CHANGES.rst | 4 | ||||
-rw-r--r-- | Cython/Compiler/ExprNodes.py | 4 | ||||
-rw-r--r-- | Cython/Utility/CythonFunction.c | 86 |
3 files changed, 60 insertions, 34 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index 8393f7d1d..0eed86c31 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -17,6 +17,10 @@ Features added Bugs fixed ---------- +* Creating a fused function attached it to the garbage collector before it + was fully initialised, thus risking crashes in rare failure cases. + Original patch by achernomorov. (Github issue #3215) + * The compilation cache in ``cython.inline("…")`` failed to take the language level into account. Patch by will-ca. (Github issue #3419) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 19e7d733a..80dec9abf 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -9387,11 +9387,11 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): if self.specialized_cpdefs or self.is_specialization: code.globalstate.use_utility_code( UtilityCode.load_cached("FusedFunction", "CythonFunction.c")) - constructor = "__pyx_FusedFunction_NewEx" + constructor = "__pyx_FusedFunction_New" else: code.globalstate.use_utility_code( UtilityCode.load_cached("CythonFunction", "CythonFunction.c")) - constructor = "__Pyx_CyFunction_NewEx" + constructor = "__Pyx_CyFunction_New" if self.code_object: code_object_result = self.code_object.py_result() diff --git a/Cython/Utility/CythonFunction.c b/Cython/Utility/CythonFunction.c index 25114d6bc..8f2349722 100644 --- a/Cython/Utility/CythonFunction.c +++ b/Cython/Utility/CythonFunction.c @@ -1,6 +1,6 @@ +//////////////////// CythonFunctionShared.proto //////////////////// -//////////////////// CythonFunction.proto //////////////////// #define __Pyx_CyFunction_USED 1 #define __Pyx_CYFUNCTION_STATICMETHOD 0x01 @@ -50,10 +50,7 @@ static PyTypeObject *__pyx_CyFunctionType = 0; #define __Pyx_CyFunction_Check(obj) (__Pyx_TypeCheck(obj, __pyx_CyFunctionType)) -#define __Pyx_CyFunction_NewEx(ml, flags, qualname, self, module, globals, code) \ - __Pyx_CyFunction_New(__pyx_CyFunctionType, ml, flags, qualname, self, module, globals, code) - -static PyObject *__Pyx_CyFunction_New(PyTypeObject *, PyMethodDef *ml, +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, int flags, PyObject* qualname, PyObject *self, PyObject *module, PyObject *globals, @@ -72,7 +69,8 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, static int __pyx_CyFunction_init(void); -//////////////////// CythonFunction //////////////////// + +//////////////////// CythonFunctionShared //////////////////// //@substitute: naming //@requires: CommonStructures.c::FetchCommonType ////@requires: ObjectHandling.c::PyObjectGetAttrStr @@ -446,11 +444,9 @@ static PyMethodDef __pyx_CyFunction_methods[] = { #define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func.m_weakreflist) #endif - -static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags, PyObject* qualname, - PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { - __pyx_CyFunctionObject *op = PyObject_GC_New(__pyx_CyFunctionObject, type); - if (op == NULL) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + if (unlikely(op == NULL)) return NULL; op->flags = flags; __Pyx_CyFunction_weakreflist(op) = NULL; @@ -478,7 +474,6 @@ static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int f op->defaults_kwdict = NULL; op->defaults_getter = NULL; op->func_annotations = NULL; - PyObject_GC_Track(op); return (PyObject *) op; } @@ -779,11 +774,36 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, Py Py_INCREF(dict); } + +//////////////////// CythonFunction.proto //////////////////// + +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +//////////////////// CythonFunction //////////////////// +//@requires: CythonFunctionShared + +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + + //////////////////// CyFunctionClassCell.proto //////////////////// static int __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions, PyObject *classobj);/*proto*/ //////////////////// CyFunctionClassCell //////////////////// -//@requires: CythonFunction +//@requires: CythonFunctionShared static int __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions, PyObject *classobj) { Py_ssize_t i, count = PyList_GET_SIZE(cyfunctions); @@ -806,7 +826,9 @@ static int __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions, PyObject *class return 0; } + //////////////////// FusedFunction.proto //////////////////// + typedef struct { __pyx_CyFunctionObject func; PyObject *__signatures__; @@ -814,11 +836,8 @@ typedef struct { PyObject *self; } __pyx_FusedFunctionObject; -#define __pyx_FusedFunction_NewEx(ml, flags, qualname, self, module, globals, code) \ - __pyx_FusedFunction_New(__pyx_FusedFunctionType, ml, flags, qualname, self, module, globals, code) -static PyObject *__pyx_FusedFunction_New(PyTypeObject *type, - PyMethodDef *ml, int flags, - PyObject *qualname, PyObject *self, +static PyObject *__pyx_FusedFunction_New(PyMethodDef *ml, int flags, + PyObject *qualname, PyObject *closure, PyObject *module, PyObject *globals, PyObject *code); @@ -829,24 +848,27 @@ static int __pyx_FusedFunction_init(void); #define __Pyx_FusedFunction_USED //////////////////// FusedFunction //////////////////// -//@requires: CythonFunction +//@requires: CythonFunctionShared static PyObject * -__pyx_FusedFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags, - PyObject *qualname, PyObject *self, +__pyx_FusedFunction_New(PyMethodDef *ml, int flags, + PyObject *qualname, PyObject *closure, PyObject *module, PyObject *globals, PyObject *code) { - __pyx_FusedFunctionObject *fusedfunc = - (__pyx_FusedFunctionObject *) __Pyx_CyFunction_New(type, ml, flags, qualname, - self, module, globals, code); - if (!fusedfunc) - return NULL; - - fusedfunc->__signatures__ = NULL; - fusedfunc->type = NULL; - fusedfunc->self = NULL; - return (PyObject *) fusedfunc; + PyObject *op = __Pyx_CyFunction_Init( + // __pyx_CyFunctionObject is correct below since that's the cast that we want. + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_FusedFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + __pyx_FusedFunctionObject *fusedfunc = (__pyx_FusedFunctionObject *) op; + fusedfunc->__signatures__ = NULL; + fusedfunc->type = NULL; + fusedfunc->self = NULL; + PyObject_GC_Track(op); + } + return op; } static void @@ -896,7 +918,7 @@ __pyx_FusedFunction_descr_get(PyObject *self, PyObject *obj, PyObject *type) if (obj == Py_None) obj = NULL; - meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_NewEx( + meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_New( ((PyCFunctionObject *) func)->m_ml, ((__pyx_CyFunctionObject *) func)->flags, ((__pyx_CyFunctionObject *) func)->func_qualname, |