bpo-9263: Dump Python object on GC assertion failure (GH-10062)

Changes:

* Add _PyObject_AssertFailed() function.
* Add _PyObject_ASSERT() and _PyObject_ASSERT_WITH_MSG() macros.
* gc_decref(): replace assert() with _PyObject_ASSERT_WITH_MSG() to
  dump the faulty object if the assertion fails.

_PyObject_AssertFailed() calls:

* _PyMem_DumpTraceback(): try to log the traceback where the object
  memory has been allocated if tracemalloc is enabled.
* _PyObject_Dump(): log repr(obj).
* Py_FatalError(): log the current Python traceback.

_PyObject_AssertFailed() uses _PyObject_IsFreed() heuristic to check
if the object memory has been freed by a debug hook on Python memory
allocators.

Initial patch written by David Malcolm.

Co-Authored-By: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
Victor Stinner 2018-10-25 17:31:10 +02:00 committed by GitHub
parent 18618e652c
commit 626bff8568
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 180 additions and 14 deletions

View file

@ -62,6 +62,12 @@ module gc
// most gc_list_* functions for it.
#define NEXT_MASK_UNREACHABLE (1)
/* Get an object's GC head */
#define AS_GC(o) ((PyGC_Head *)(o)-1)
/* Get the object given the GC head */
#define FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1))
static inline int
gc_is_collecting(PyGC_Head *g)
{
@ -98,16 +104,12 @@ gc_reset_refs(PyGC_Head *g, Py_ssize_t refs)
static inline void
gc_decref(PyGC_Head *g)
{
assert(gc_get_refs(g) > 0);
_PyObject_ASSERT_WITH_MSG(FROM_GC(g),
gc_get_refs(g) > 0,
"refcount is too small");
g->_gc_prev -= 1 << _PyGC_PREV_SHIFT;
}
/* Get an object's GC head */
#define AS_GC(o) ((PyGC_Head *)(o)-1)
/* Get the object given the GC head */
#define FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1))
/* Python string to use if unhandled exception occurs */
static PyObject *gc_str = NULL;