Skip to content

Commit

Permalink
pythongh-112529: Track if debug allocator is used as underlying alloc…
Browse files Browse the repository at this point in the history
…ator

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.
  • Loading branch information
colesbury committed Jan 16, 2024
1 parent a424736 commit 24e41e3
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 6 deletions.
3 changes: 3 additions & 0 deletions Include/internal/pycore_pymem.h
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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
}
Expand Down
2 changes: 2 additions & 0 deletions Include/internal/pycore_pymem_init.h
Expand Up @@ -70,13 +70,15 @@ 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) \
{ \
PYRAW_ALLOC, \
PYMEM_ALLOC, \
PYOBJ_ALLOC, \
}
# define _pymem_is_debug_enabled_INIT 0
#endif

#define _pymem_allocators_debug_INIT \
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_runtime_init.h
Expand Up @@ -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, \
Expand Down
25 changes: 19 additions & 6 deletions Objects/obmalloc.c
Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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();
}

Expand All @@ -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;
Expand Down Expand Up @@ -604,13 +612,17 @@ _PyMem_GetCurrentAllocatorName(void)
}


#ifdef WITH_PYMALLOC
static int
int
_PyMem_DebugEnabled(void)
{
return (_PyObject.malloc == _PyMem_DebugMalloc);
#ifdef WITH_PYMALLOC
return _PyRuntime.allocators.is_debug_enabled;
#else
return 0;
#endif
}

#ifdef WITH_PYMALLOC
static int
_PyMem_PymallocEnabled(void)
{
Expand Down Expand Up @@ -695,6 +707,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
Expand Down

0 comments on commit 24e41e3

Please sign in to comment.