]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-112529: Track if debug allocator is used as underlying allocator (#113747)
authorSam Gross <colesbury@gmail.com>
Tue, 16 Jan 2024 21:42:15 +0000 (16:42 -0500)
committerGitHub <noreply@github.com>
Tue, 16 Jan 2024 21:42:15 +0000 (13:42 -0800)
* gh-112529: Track if debug allocator is used as underlying allocator

The GC implementation for free-threaded builds will need to accurately
detect if the debug allocator is used because it affects the offset of
the Python object from the beginning of the memory allocation. The
current implementation of `_PyMem_DebugEnabled` only considers if the
debug allocator is the outer-most allocator; it doesn't handle the case
of "hooks" like tracemalloc being used on top of the debug allocator.

This change enables more accurate detection of the debug allocator by
tracking when debug hooks are enabled.

* Simplify _PyMem_DebugEnabled

Include/internal/pycore_pymem.h
Include/internal/pycore_pymem_init.h
Include/internal/pycore_runtime_init.h
Objects/obmalloc.c

index c49742e177a13016a34020872c34cbed4ec738ee..1a72d07b50b738e2ee863fb7421e52f68b9da804 100644 (file)
@@ -44,6 +44,7 @@ struct _pymem_allocators {
         debug_alloc_api_t mem;
         debug_alloc_api_t obj;
     } debug;
+    int is_debug_enabled;
     PyObjectArenaAllocator obj_arena;
 };
 
@@ -106,6 +107,8 @@ extern int _PyMem_GetAllocatorName(
    PYMEM_ALLOCATOR_NOT_SET does nothing. */
 extern int _PyMem_SetupAllocators(PyMemAllocatorName allocator);
 
+/* Is the debug allocator enabled? */
+extern int _PyMem_DebugEnabled(void);
 
 #ifdef __cplusplus
 }
index 360fb9218a9cdac0efcc770a64eb9870dff29cc5..96c49ed7338d6d6a34d2808ef0f4841038346c1f 100644 (file)
@@ -70,6 +70,7 @@ extern void _PyMem_ArenaFree(void *, void *, size_t);
         PYDBGMEM_ALLOC(runtime), \
         PYDBGOBJ_ALLOC(runtime), \
     }
+# define _pymem_is_debug_enabled_INIT 1
 #else
 # define _pymem_allocators_standard_INIT(runtime) \
     { \
@@ -77,6 +78,7 @@ extern void _PyMem_ArenaFree(void *, void *, size_t);
         PYMEM_ALLOC, \
         PYOBJ_ALLOC, \
     }
+# define _pymem_is_debug_enabled_INIT 0
 #endif
 
 #define _pymem_allocators_debug_INIT \
index d324a94278839c09fcd04cf20bcdc713748511fe..5f47d60de37825b67d655b40ce848577e2549019 100644 (file)
@@ -86,6 +86,7 @@ extern PyTypeObject _PyExc_MemoryError;
             .standard = _pymem_allocators_standard_INIT(runtime), \
             .debug = _pymem_allocators_debug_INIT, \
             .obj_arena = _pymem_allocators_obj_arena_INIT, \
+            .is_debug_enabled = _pymem_is_debug_enabled_INIT, \
         }, \
         .obmalloc = _obmalloc_global_state_INIT, \
         .pyhash_state = pyhash_state_INIT, \
index 88ad305ad776b03cfe286d29c4df50f3470bb10e..16d5bcb53e7eb7529e3ddc194e3f0b1a550ae132 100644 (file)
@@ -439,12 +439,14 @@ set_up_allocators_unlocked(PyMemAllocatorName allocator)
         (void)set_default_allocator_unlocked(PYMEM_DOMAIN_RAW, pydebug, NULL);
         (void)set_default_allocator_unlocked(PYMEM_DOMAIN_MEM, pydebug, NULL);
         (void)set_default_allocator_unlocked(PYMEM_DOMAIN_OBJ, pydebug, NULL);
+        _PyRuntime.allocators.is_debug_enabled = pydebug;
         break;
 
     case PYMEM_ALLOCATOR_DEBUG:
         (void)set_default_allocator_unlocked(PYMEM_DOMAIN_RAW, 1, NULL);
         (void)set_default_allocator_unlocked(PYMEM_DOMAIN_MEM, 1, NULL);
         (void)set_default_allocator_unlocked(PYMEM_DOMAIN_OBJ, 1, NULL);
+        _PyRuntime.allocators.is_debug_enabled = 1;
         break;
 
 #ifdef WITH_PYMALLOC
@@ -458,7 +460,9 @@ set_up_allocators_unlocked(PyMemAllocatorName allocator)
         set_allocator_unlocked(PYMEM_DOMAIN_MEM, &pymalloc);
         set_allocator_unlocked(PYMEM_DOMAIN_OBJ, &pymalloc);
 
-        if (allocator == PYMEM_ALLOCATOR_PYMALLOC_DEBUG) {
+        int is_debug = (allocator == PYMEM_ALLOCATOR_PYMALLOC_DEBUG);
+        _PyRuntime.allocators.is_debug_enabled = is_debug;
+        if (is_debug) {
             set_up_debug_hooks_unlocked();
         }
         break;
@@ -477,7 +481,9 @@ set_up_allocators_unlocked(PyMemAllocatorName allocator)
         PyMemAllocatorEx objmalloc = MIMALLOC_OBJALLOC;
         set_allocator_unlocked(PYMEM_DOMAIN_OBJ, &objmalloc);
 
-        if (allocator == PYMEM_ALLOCATOR_MIMALLOC_DEBUG) {
+        int is_debug = (allocator == PYMEM_ALLOCATOR_MIMALLOC_DEBUG);
+        _PyRuntime.allocators.is_debug_enabled = is_debug;
+        if (is_debug) {
             set_up_debug_hooks_unlocked();
         }
 
@@ -493,7 +499,9 @@ set_up_allocators_unlocked(PyMemAllocatorName allocator)
         set_allocator_unlocked(PYMEM_DOMAIN_MEM, &malloc_alloc);
         set_allocator_unlocked(PYMEM_DOMAIN_OBJ, &malloc_alloc);
 
-        if (allocator == PYMEM_ALLOCATOR_MALLOC_DEBUG) {
+        int is_debug = (allocator == PYMEM_ALLOCATOR_MALLOC_DEBUG);
+        _PyRuntime.allocators.is_debug_enabled = is_debug;
+        if (is_debug) {
             set_up_debug_hooks_unlocked();
         }
         break;
@@ -604,13 +612,13 @@ _PyMem_GetCurrentAllocatorName(void)
 }
 
 
-#ifdef WITH_PYMALLOC
-static int
+int
 _PyMem_DebugEnabled(void)
 {
-    return (_PyObject.malloc == _PyMem_DebugMalloc);
+    return _PyRuntime.allocators.is_debug_enabled;
 }
 
+#ifdef WITH_PYMALLOC
 static int
 _PyMem_PymallocEnabled(void)
 {
@@ -695,6 +703,7 @@ set_up_debug_hooks_unlocked(void)
     set_up_debug_hooks_domain_unlocked(PYMEM_DOMAIN_RAW);
     set_up_debug_hooks_domain_unlocked(PYMEM_DOMAIN_MEM);
     set_up_debug_hooks_domain_unlocked(PYMEM_DOMAIN_OBJ);
+    _PyRuntime.allocators.is_debug_enabled = 1;
 }
 
 void