summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2020-04-11 19:16:55 +0200
committerStefan Behnel <stefan_ml@behnel.de>2020-04-13 07:57:36 +0200
commitb3c2e0d6791378a7361a1cc731ff93728b6a3d16 (patch)
tree5cb4b9dfe32f4ae6ecfe2f0e17270c994bcf1253
parentacd3fdcb93261d3ce245b6359c6b1684f6ac2782 (diff)
downloadcython-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.rst4
-rw-r--r--Cython/Compiler/ExprNodes.py4
-rw-r--r--Cython/Utility/CythonFunction.c86
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,