summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2023-09-18 14:59:09 (GMT)
committerGitHub <noreply@github.com>2023-09-18 14:59:09 (GMT)
commit0bb0d88e2d4e300946e399e088e2ff60de2ccf8c (patch)
treee197a96bdf8c45937a2f839fd723a9bb58270c47 /Modules
parentef659b96169888e52b6ff03ce28fffaaa8f76818 (diff)
downloadcpython-0bb0d88e2d4e300946e399e088e2ff60de2ccf8c.zip
cpython-0bb0d88e2d4e300946e399e088e2ff60de2ccf8c.tar.gz
cpython-0bb0d88e2d4e300946e399e088e2ff60de2ccf8c.tar.bz2
gh-109496: Detect Py_DECREF() after dealloc in debug mode (#109539)
On a Python built in debug mode, Py_DECREF() now calls _Py_NegativeRefcount() if the object is a dangling pointer to deallocated memory: memory filled with 0xDD "dead byte" by the debug hook on memory allocators. The fix is to check the reference count *before* checking for _Py_IsImmortal(). Add test_decref_freed_object() to test_capi.test_misc.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_testcapimodule.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 85d8401..f356fc5 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2034,6 +2034,26 @@ negative_refcount(PyObject *self, PyObject *Py_UNUSED(args))
Py_RETURN_NONE;
}
+
+static PyObject *
+decref_freed_object(PyObject *self, PyObject *Py_UNUSED(args))
+{
+ PyObject *obj = PyUnicode_FromString("decref_freed_object");
+ if (obj == NULL) {
+ return NULL;
+ }
+ assert(Py_REFCNT(obj) == 1);
+
+ // Deallocate the memory
+ Py_DECREF(obj);
+ // obj is a now a dangling pointer
+
+ // gh-109496: If Python is built in debug mode, Py_DECREF() must call
+ // _Py_NegativeRefcount() and abort Python.
+ Py_DECREF(obj);
+
+ Py_RETURN_NONE;
+}
#endif
@@ -3299,6 +3319,7 @@ static PyMethodDef TestMethods[] = {
{"bad_get", _PyCFunction_CAST(bad_get), METH_FASTCALL},
#ifdef Py_REF_DEBUG
{"negative_refcount", negative_refcount, METH_NOARGS},
+ {"decref_freed_object", decref_freed_object, METH_NOARGS},
#endif
{"meth_varargs", meth_varargs, METH_VARARGS},
{"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS},