summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2020-05-18 09:23:28 +0200
committerStefan Behnel <stefan_ml@behnel.de>2020-05-18 09:52:04 +0200
commitf7ca5efbc97d22466b8e85eb3f5aae5d96cc8837 (patch)
tree09514550838f3b962a9e275c6bb975a562192022
parentb177f2296686833a3903e0b8a7dcf4afbed2e56d (diff)
downloadcython-f7ca5efbc97d22466b8e85eb3f5aae5d96cc8837.tar.gz
Disable GC during hacked calls to PyType_Ready() that simulate a heap type for an actual non-heap type, because it can lead to crashes if GC visits such a hacked type.
Closes https://github.com/cython/cython/issues/3603
-rw-r--r--Cython/Utility/ExtensionTypes.c62
1 files changed, 53 insertions, 9 deletions
diff --git a/Cython/Utility/ExtensionTypes.c b/Cython/Utility/ExtensionTypes.c
index 5c700cf93..e2af385ee 100644
--- a/Cython/Utility/ExtensionTypes.c
+++ b/Cython/Utility/ExtensionTypes.c
@@ -55,20 +55,64 @@ static int __Pyx_PyType_Ready(PyTypeObject *t) {
}
#if PY_VERSION_HEX >= 0x03050000
- // As of https://bugs.python.org/issue22079
- // PyType_Ready enforces that all bases of a non-heap type are
- // non-heap. We know that this is the case for the solid base but
- // other bases are heap allocated and are kept alive through the
- // tp_bases reference.
- // Other than this check, the Py_TPFLAGS_HEAPTYPE flag is unused
- // in PyType_Ready().
- t->tp_flags |= Py_TPFLAGS_HEAPTYPE;
+ {
+ // Make sure GC does not pick up our non-heap type as heap type with this hack!
+ PyObject *ret, *py_status;
+ int gc_was_enabled;
+ PyObject *gc = PyImport_Import(PYUNICODE("gc"));
+ if (unlikely(!gc)) return -1;
+ py_status = PyObject_CallMethodObjArgs(gc, PYUNICODE("isenabled"), NULL);
+ if (unlikely(!py_status)) {
+ Py_DECREF(gc);
+ return -1;
+ }
+ gc_was_enabled = __Pyx_PyObject_IsTrue(py_status);
+ Py_DECREF(py_status);
+ if (gc_was_enabled > 0) {
+ ret = PyObject_CallMethodObjArgs(gc, PYUNICODE("disable"), NULL);
+ if (unlikely(!ret)) {
+ Py_DECREF(gc);
+ return -1;
+ }
+ Py_DECREF(ret);
+ } else if (unlikely(gc_was_enabled == -1)) {
+ Py_DECREF(gc);
+ return -1;
+ }
+
+ // As of https://bugs.python.org/issue22079
+ // PyType_Ready enforces that all bases of a non-heap type are
+ // non-heap. We know that this is the case for the solid base but
+ // other bases are heap allocated and are kept alive through the
+ // tp_bases reference.
+ // Other than this check, the Py_TPFLAGS_HEAPTYPE flag is unused
+ // in PyType_Ready().
+ t->tp_flags |= Py_TPFLAGS_HEAPTYPE;
#endif
r = PyType_Ready(t);
#if PY_VERSION_HEX >= 0x03050000
- t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE;
+ t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE;
+
+ if (gc_was_enabled) {
+ PyObject *t, *v, *tb;
+ PyErr_Fetch(&t, &v, &tb);
+ ret = PyObject_CallMethodObjArgs(gc, PYUNICODE("enable"), NULL);
+ if (likely(ret || r == -1)) {
+ Py_XDECREF(ret);
+ // do not overwrite exceptions raised by PyType_Ready() above
+ PyErr_Restore(t, v, tb);
+ } else {
+ // PyType_Ready() succeeded, but gc.enable() failed.
+ Py_XDECREF(t);
+ Py_XDECREF(v);
+ Py_XDECREF(tb);
+ r = -1;
+ }
+ }
+ Py_DECREF(gc);
+ }
#endif
return r;