PyAPI_FUNC(Py_ssize_t) _Py_UTF8_Edit_Cost(PyObject *str_a, PyObject *str_b,
Py_ssize_t max_cost);
+PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc(
+ const char *func,
+ const char *message);
+
+#define _Py_FatalRefcountError(message) _Py_FatalRefcountErrorFunc(__func__, message)
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+Add a deallocator to the bool type to detect refcount bugs in C extensions
+which call Py_DECREF(Py_True) or Py_DECREF(Py_False) by mistake. Detect also
+refcount bugs when the empty tuple singleton is destroyed by mistake. Patch
+by Victor Stinner.
/* Boolean type, a subtype of int */
#include "Python.h"
+#include "pycore_pyerrors.h" // _Py_FatalRefcountError()
#include "longintrepr.h"
/* We define bool_repr to return "False" or "True" */
static void _Py_NO_RETURN
bool_dealloc(PyObject* Py_UNUSED(ignore))
{
- Py_FatalError("deallocating True or False likely caused by "
- "a refcount bug in a C extension");
+ _Py_FatalRefcountError("deallocating True or False");
}
/* The type object for bool. Note that this cannot be subclassed! */
static void _Py_NO_RETURN
none_dealloc(PyObject* Py_UNUSED(ignore))
{
- Py_FatalError("deallocating None likely caused by a refcount bug "
- "in a C extension");
+ _Py_FatalRefcountError("deallocating None");
}
static PyObject *
#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"
}
#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
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
}
}
+void _Py_NO_RETURN
+_Py_FatalRefcountErrorFunc(const char *func, const char *msg)
+{
+ _Py_FatalErrorFormat(func,
+ "%s: bug likely caused by a refcount error "
+ "in a C extension",
+ msg);
+}
+
+
void _Py_NO_RETURN
Py_ExitStatusException(PyStatus status)
{