summaryrefslogtreecommitdiff
path: root/Include
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@redhat.com>2018-10-25 17:31:10 +0200
committerGitHub <noreply@github.com>2018-10-25 17:31:10 +0200
commit626bff856840f471e98ec627043f780c111a063d (patch)
tree4c8f4da76f3443157e7a06a96d88bbc631650f88 /Include
parent18618e652c56e61a134e596b315a13c7cb997a89 (diff)
downloadcpython-git-626bff856840f471e98ec627043f780c111a063d.tar.gz
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>
Diffstat (limited to 'Include')
-rw-r--r--Include/object.h47
-rw-r--r--Include/pymem.h2
2 files changed, 48 insertions, 1 deletions
diff --git a/Include/object.h b/Include/object.h
index 8b2afc2bc5..4a49609c72 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -1105,6 +1105,53 @@ PyAPI_FUNC(void)
_PyObject_DebugTypeStats(FILE *out);
#endif /* ifndef Py_LIMITED_API */
+
+#ifndef Py_LIMITED_API
+/* Define a pair of assertion macros:
+ _PyObject_ASSERT_WITH_MSG() and _PyObject_ASSERT().
+
+ These work like the regular C assert(), in that they will abort the
+ process with a message on stderr if the given condition fails to hold,
+ but compile away to nothing if NDEBUG is defined.
+
+ However, before aborting, Python will also try to call _PyObject_Dump() on
+ the given object. This may be of use when investigating bugs in which a
+ particular object is corrupt (e.g. buggy a tp_visit method in an extension
+ module breaking the garbage collector), to help locate the broken objects.
+
+ The WITH_MSG variant allows you to supply an additional message that Python
+ will attempt to print to stderr, after the object dump. */
+#ifdef NDEBUG
+ /* No debugging: compile away the assertions: */
+# define _PyObject_ASSERT_WITH_MSG(obj, expr, msg) ((void)0)
+#else
+ /* With debugging: generate checks: */
+# define _PyObject_ASSERT_WITH_MSG(obj, expr, msg) \
+ ((expr) \
+ ? (void)(0) \
+ : _PyObject_AssertFailed((obj), \
+ (msg), \
+ Py_STRINGIFY(expr), \
+ __FILE__, \
+ __LINE__, \
+ __func__))
+#endif
+
+#define _PyObject_ASSERT(obj, expr) _PyObject_ASSERT_WITH_MSG(obj, expr, NULL)
+
+/* Declare and define _PyObject_AssertFailed() even when NDEBUG is defined,
+ to avoid causing compiler/linker errors when building extensions without
+ NDEBUG against a Python built with NDEBUG defined. */
+PyAPI_FUNC(void) _PyObject_AssertFailed(
+ PyObject *obj,
+ const char *msg,
+ const char *expr,
+ const char *file,
+ int line,
+ const char *function);
+#endif /* ifndef Py_LIMITED_API */
+
+
#ifdef __cplusplus
}
#endif
diff --git a/Include/pymem.h b/Include/pymem.h
index e993628a21..19f0c8a2d9 100644
--- a/Include/pymem.h
+++ b/Include/pymem.h
@@ -196,7 +196,7 @@ PyAPI_FUNC(void) PyMem_SetAllocator(PyMemAllocatorDomain domain,
The function does nothing if Python is not compiled is debug mode. */
PyAPI_FUNC(void) PyMem_SetupDebugHooks(void);
-#endif
+#endif /* Py_LIMITED_API */
#ifdef Py_BUILD_CORE
/* Set the memory allocator of the specified domain to the default.