diff options
author | Victor Stinner <vstinner@python.org> | 2021-09-21 21:04:34 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-21 21:04:34 (GMT) |
commit | 79a31480992c3fa5890fc7a6c5d9af6d337d5844 (patch) | |
tree | a3ef89bb0340669e86c52f5b924cfb0e71845956 /Objects/tupleobject.c | |
parent | f604cf1c377a7648e0686044e6e49900bfc9feef (diff) | |
download | cpython-79a31480992c3fa5890fc7a6c5d9af6d337d5844.zip cpython-79a31480992c3fa5890fc7a6c5d9af6d337d5844.tar.gz cpython-79a31480992c3fa5890fc7a6c5d9af6d337d5844.tar.bz2 |
bpo-45061: Detect refcount bug on empty tuple singleton (GH-28503)
Detect refcount bugs in C extensions when the empty tuple singleton
is destroyed by mistake.
Add the _Py_FatalRefcountErrorFunc() function.
Diffstat (limited to 'Objects/tupleobject.c')
-rw-r--r-- | Objects/tupleobject.c | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 3e3aea4..e64b93b 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -6,6 +6,7 @@ #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_object.h" // _PyObject_GC_TRACK() +#include "pycore_pyerrors.h" // _Py_FatalRefcountError() /*[clinic input] class tuple "PyTupleObject *" "&PyTuple_Type" @@ -287,6 +288,17 @@ tupledealloc(PyTupleObject *op) } #endif } +#if defined(Py_DEBUG) && PyTuple_MAXSAVESIZE > 0 + else { + assert(len == 0); + struct _Py_tuple_state *state = get_tuple_state(); + // The empty tuple singleton must only be deallocated by + // _PyTuple_Fini(): not before, not after + if (op == state->free_list[0] && state->numfree[0] != 0) { + _Py_FatalRefcountError("deallocating the empty tuple singleton"); + } + } +#endif Py_TYPE(op)->tp_free((PyObject *)op); #if PyTuple_MAXSAVESIZE > 0 @@ -1048,11 +1060,16 @@ _PyTuple_Fini(PyInterpreterState *interp) struct _Py_tuple_state *state = &interp->tuple; // The empty tuple singleton must not be tracked by the GC assert(!_PyObject_GC_IS_TRACKED(state->free_list[0])); + +#ifdef Py_DEBUG + state->numfree[0] = 0; +#endif Py_CLEAR(state->free_list[0]); - _PyTuple_ClearFreeList(interp); #ifdef Py_DEBUG state->numfree[0] = -1; #endif + + _PyTuple_ClearFreeList(interp); #endif } |