struct llist_node head; // queue of _mem_work_chunk items
};
-/* Set the memory allocator of the specified domain to the default.
- Save the old allocator into *old_alloc if it's non-NULL.
- Return on success, or return -1 if the domain is unknown. */
-extern int _PyMem_SetDefaultAllocator(
- PyMemAllocatorDomain domain,
- PyMemAllocatorEx *old_alloc);
-
/* Special bytes broadcast into debug memory blocks at appropriate times.
Strings of these are unlikely to be valid addresses, floats, ints or
7-bit ASCII.
PYMEM_ALLOCATOR_NOT_SET does nothing. */
extern int _PyMem_SetupAllocators(PyMemAllocatorName allocator);
+// Default raw memory allocator that is not affected by PyMem_SetAllocator()
+extern void *_PyMem_DefaultRawMalloc(size_t);
+extern void *_PyMem_DefaultRawCalloc(size_t, size_t);
+extern void *_PyMem_DefaultRawRealloc(void *, size_t);
+extern void _PyMem_DefaultRawFree(void *);
+extern wchar_t *_PyMem_DefaultRawWcsdup(const wchar_t *str);
+
/* Is the debug allocator enabled? */
extern int _PyMem_DebugEnabled(void);
// Periodically process delayed free requests.
extern void _PyMem_ProcessDelayed(PyThreadState *tstate);
-
// Periodically process delayed free requests when the world is stopped.
// Notify of any objects whic should be freeed.
typedef void (*delayed_dealloc_cb)(PyObject *, void *);
#define PYDBGOBJ_ALLOC \
{&_PyRuntime.allocators.debug.obj, _PyMem_DebugMalloc, _PyMem_DebugCalloc, _PyMem_DebugRealloc, _PyMem_DebugFree}
+/* default raw allocator (not swappable) */
+
+void *
+_PyMem_DefaultRawMalloc(size_t size)
+{
+#ifdef Py_DEBUG
+ return _PyMem_DebugRawMalloc(&_PyRuntime.allocators.debug.raw, size);
+#else
+ return _PyMem_RawMalloc(NULL, size);
+#endif
+}
+
+void *
+_PyMem_DefaultRawCalloc(size_t nelem, size_t elsize)
+{
+#ifdef Py_DEBUG
+ return _PyMem_DebugRawCalloc(&_PyRuntime.allocators.debug.raw, nelem, elsize);
+#else
+ return _PyMem_RawCalloc(NULL, nelem, elsize);
+#endif
+}
+
+void *
+_PyMem_DefaultRawRealloc(void *ptr, size_t size)
+{
+#ifdef Py_DEBUG
+ return _PyMem_DebugRawRealloc(&_PyRuntime.allocators.debug.raw, ptr, size);
+#else
+ return _PyMem_RawRealloc(NULL, ptr, size);
+#endif
+}
+
+void
+_PyMem_DefaultRawFree(void *ptr)
+{
+#ifdef Py_DEBUG
+ _PyMem_DebugRawFree(&_PyRuntime.allocators.debug.raw, ptr);
+#else
+ _PyMem_RawFree(NULL, ptr);
+#endif
+}
+
+wchar_t*
+_PyMem_DefaultRawWcsdup(const wchar_t *str)
+{
+ assert(str != NULL);
+
+ size_t len = wcslen(str);
+ if (len > (size_t)PY_SSIZE_T_MAX / sizeof(wchar_t) - 1) {
+ return NULL;
+ }
+
+ size_t size = (len + 1) * sizeof(wchar_t);
+ wchar_t *str2 = _PyMem_DefaultRawMalloc(size);
+ if (str2 == NULL) {
+ return NULL;
+ }
+
+ memcpy(str2, str, size);
+ return str2;
+}
+
/* the low-level virtual memory allocator */
#ifdef WITH_PYMALLOC
static const int pydebug = 0;
#endif
-int
-_PyMem_SetDefaultAllocator(PyMemAllocatorDomain domain,
- PyMemAllocatorEx *old_alloc)
-{
- PyMutex_Lock(&ALLOCATORS_MUTEX);
- int res = set_default_allocator_unlocked(domain, pydebug, old_alloc);
- PyMutex_Unlock(&ALLOCATORS_MUTEX);
- return res;
-}
-
-
int
_PyMem_GetAllocatorName(const char *name, PyMemAllocatorName *allocator)
{
#include "pycore_pyerrors.h" // _PyErr_SetString()
#include "pycore_pyhash.h" // _Py_KeyedHash()
#include "pycore_pylifecycle.h"
-#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
+#include "pycore_pymem.h" // _PyMem_DefaultRawFree()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_sysmodule.h" // _PySys_ClearAttrString()
#include "pycore_time.h" // _PyTime_AsMicroseconds()
/* Force default raw memory allocator to get a known allocator to be able
to release the memory in _PyImport_Fini2() */
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
/* Allocate new memory for the combined table */
p = NULL;
if (i + n <= SIZE_MAX / sizeof(struct _inittab) - 1) {
size_t size = sizeof(struct _inittab) * (i + n + 1);
- p = PyMem_RawRealloc(inittab_copy, size);
+ p = _PyMem_DefaultRawRealloc(inittab_copy, size);
}
if (p == NULL) {
res = -1;
}
memcpy(p + i, newtab, (n + 1) * sizeof(struct _inittab));
PyImport_Inittab = inittab_copy = p;
-
done:
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
return res;
}
size++;
/* Make the copy. */
- struct _inittab *copied = PyMem_RawMalloc(size * sizeof(struct _inittab));
+ struct _inittab *copied = _PyMem_DefaultRawMalloc(size * sizeof(struct _inittab));
if (copied == NULL) {
return -1;
}
{
struct _inittab *inittab = INITTAB;
INITTAB = NULL;
- PyMem_RawFree(inittab);
+ _PyMem_DefaultRawFree(inittab);
}
PyObject *
if (INITTAB != NULL) {
return _PyStatus_ERR("global import state already initialized");
}
-
- PyStatus status = _PyStatus_OK();
-
- /* Force default raw memory allocator to get a known allocator to be able
- to release the memory in _PyImport_Fini() */
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
if (init_builtin_modules_table() != 0) {
- status = PyStatus_NoMemory();
- goto done;
+ return PyStatus_NoMemory();
}
-
-done:
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
- return status;
+ return _PyStatus_OK();
}
void
// ever dlclose() the module files?
_extensions_cache_clear_all();
- /* Use the same memory allocator as _PyImport_Init(). */
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
/* Free memory allocated by _PyImport_Init() */
fini_builtin_modules_table();
-
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
}
void
_PyImport_Fini2(void)
{
- /* Use the same memory allocator than PyImport_ExtendInittab(). */
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
// Reset PyImport_Inittab
PyImport_Inittab = _PyImport_Inittab;
/* Free memory allocated by PyImport_ExtendInittab() */
- PyMem_RawFree(inittab_copy);
+ _PyMem_DefaultRawFree(inittab_copy);
inittab_copy = NULL;
-
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
}
#include "pycore_pathconfig.h" // _Py_path_config
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
#include "pycore_pylifecycle.h" // _Py_PreInitializeFromConfig()
-#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
+#include "pycore_pymem.h" // _PyMem_DefaultRawMalloc()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_pystats.h" // _Py_StatsOn()
#include "pycore_sysmodule.h" // _PySys_SetIntMaxStrDigits()
#endif /* Py_DEBUG */
-void
-_PyWideStringList_Clear(PyWideStringList *list)
+static void
+_PyWideStringList_ClearEx(PyWideStringList *list,
+ bool use_default_allocator)
{
assert(_PyWideStringList_CheckConsistency(list));
for (Py_ssize_t i=0; i < list->length; i++) {
- PyMem_RawFree(list->items[i]);
+ if (use_default_allocator) {
+ _PyMem_DefaultRawFree(list->items[i]);
+ }
+ else {
+ PyMem_RawFree(list->items[i]);
+ }
+ }
+ if (use_default_allocator) {
+ _PyMem_DefaultRawFree(list->items);
+ }
+ else {
+ PyMem_RawFree(list->items);
}
- PyMem_RawFree(list->items);
list->length = 0;
list->items = NULL;
}
+void
+_PyWideStringList_Clear(PyWideStringList *list)
+{
+ _PyWideStringList_ClearEx(list, false);
+}
-int
-_PyWideStringList_Copy(PyWideStringList *list, const PyWideStringList *list2)
+static int
+_PyWideStringList_CopyEx(PyWideStringList *list,
+ const PyWideStringList *list2,
+ bool use_default_allocator)
{
assert(_PyWideStringList_CheckConsistency(list));
assert(_PyWideStringList_CheckConsistency(list2));
if (list2->length == 0) {
- _PyWideStringList_Clear(list);
+ _PyWideStringList_ClearEx(list, use_default_allocator);
return 0;
}
PyWideStringList copy = _PyWideStringList_INIT;
size_t size = list2->length * sizeof(list2->items[0]);
- copy.items = PyMem_RawMalloc(size);
+ if (use_default_allocator) {
+ copy.items = _PyMem_DefaultRawMalloc(size);
+ }
+ else {
+ copy.items = PyMem_RawMalloc(size);
+ }
if (copy.items == NULL) {
return -1;
}
for (Py_ssize_t i=0; i < list2->length; i++) {
- wchar_t *item = _PyMem_RawWcsdup(list2->items[i]);
+ wchar_t *item;
+ if (use_default_allocator) {
+ item = _PyMem_DefaultRawWcsdup(list2->items[i]);
+ }
+ else {
+ item = _PyMem_RawWcsdup(list2->items[i]);
+ }
if (item == NULL) {
- _PyWideStringList_Clear(©);
+ _PyWideStringList_ClearEx(©, use_default_allocator);
return -1;
}
copy.items[i] = item;
copy.length = i + 1;
}
- _PyWideStringList_Clear(list);
+ _PyWideStringList_ClearEx(list, use_default_allocator);
*list = copy;
return 0;
}
+int
+_PyWideStringList_Copy(PyWideStringList *list, const PyWideStringList *list2)
+{
+ return _PyWideStringList_CopyEx(list, list2, false);
+}
PyStatus
PyWideStringList_Insert(PyWideStringList *list,
void
_Py_ClearArgcArgv(void)
{
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
- _PyWideStringList_Clear(&_PyRuntime.orig_argv);
-
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+ _PyWideStringList_ClearEx(&_PyRuntime.orig_argv, true);
}
_Py_SetArgcArgv(Py_ssize_t argc, wchar_t * const *argv)
{
const PyWideStringList argv_list = {.length = argc, .items = (wchar_t **)argv};
- int res;
-
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
// XXX _PyRuntime.orig_argv only gets cleared by Py_Main(),
// so it currently leaks for embedders.
- res = _PyWideStringList_Copy(&_PyRuntime.orig_argv, &argv_list);
-
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
- return res;
+ return _PyWideStringList_CopyEx(&_PyRuntime.orig_argv, &argv_list, true);
}
#include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_fileutils.h" // _Py_wgetcwd()
#include "pycore_pathconfig.h"
-#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
+#include "pycore_pymem.h" // _PyMem_DefaultRawFree()
#include <wchar.h>
#include "marshal.h" // PyMarshal_ReadObjectFromString
void
_PyPathConfig_ClearGlobal(void)
{
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
#define CLEAR(ATTR) \
do { \
- PyMem_RawFree(_Py_path_config.ATTR); \
+ _PyMem_DefaultRawFree(_Py_path_config.ATTR); \
_Py_path_config.ATTR = NULL; \
} while (0)
_Py_path_config._is_python_build = 0;
#undef CLEAR
-
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
}
PyStatus
PyStatus
_PyPathConfig_UpdateGlobal(const PyConfig *config)
{
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
#define COPY(ATTR) \
do { \
if (config->ATTR) { \
- PyMem_RawFree(_Py_path_config.ATTR); \
- _Py_path_config.ATTR = _PyMem_RawWcsdup(config->ATTR); \
+ _PyMem_DefaultRawFree(_Py_path_config.ATTR); \
+ _Py_path_config.ATTR = _PyMem_DefaultRawWcsdup(config->ATTR); \
if (!_Py_path_config.ATTR) goto error; \
} \
} while (0)
#define COPY2(ATTR, SRCATTR) \
do { \
if (config->SRCATTR) { \
- PyMem_RawFree(_Py_path_config.ATTR); \
- _Py_path_config.ATTR = _PyMem_RawWcsdup(config->SRCATTR); \
+ _PyMem_DefaultRawFree(_Py_path_config.ATTR); \
+ _Py_path_config.ATTR = _PyMem_DefaultRawWcsdup(config->SRCATTR); \
if (!_Py_path_config.ATTR) goto error; \
} \
} while (0)
#undef COPY2
#undef COPY_INT
- PyMem_RawFree(_Py_path_config.module_search_path);
+ _PyMem_DefaultRawFree(_Py_path_config.module_search_path);
_Py_path_config.module_search_path = NULL;
- PyMem_RawFree(_Py_path_config.calculated_module_search_path);
+ _PyMem_DefaultRawFree(_Py_path_config.calculated_module_search_path);
_Py_path_config.calculated_module_search_path = NULL;
do {
cch += 1 + wcslen(config->module_search_paths.items[i]);
}
- wchar_t *path = (wchar_t*)PyMem_RawMalloc(sizeof(wchar_t) * cch);
+ wchar_t *path = (wchar_t*)_PyMem_DefaultRawMalloc(sizeof(wchar_t) * cch);
if (!path) {
goto error;
}
_Py_path_config.calculated_module_search_path = path;
} while (0);
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
return _PyStatus_OK();
error:
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
return _PyStatus_NO_MEMORY();
}
return;
}
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+ _PyMem_DefaultRawFree(_Py_path_config.prefix);
+ _PyMem_DefaultRawFree(_Py_path_config.exec_prefix);
+ _PyMem_DefaultRawFree(_Py_path_config.stdlib_dir);
+ _PyMem_DefaultRawFree(_Py_path_config.module_search_path);
+ _PyMem_DefaultRawFree(_Py_path_config.calculated_module_search_path);
- PyMem_RawFree(_Py_path_config.prefix);
- PyMem_RawFree(_Py_path_config.exec_prefix);
- PyMem_RawFree(_Py_path_config.stdlib_dir);
- PyMem_RawFree(_Py_path_config.module_search_path);
- PyMem_RawFree(_Py_path_config.calculated_module_search_path);
-
- _Py_path_config.prefix = _PyMem_RawWcsdup(L"");
- _Py_path_config.exec_prefix = _PyMem_RawWcsdup(L"");
+ _Py_path_config.prefix = _PyMem_DefaultRawWcsdup(L"");
+ _Py_path_config.exec_prefix = _PyMem_DefaultRawWcsdup(L"");
// XXX Copy this from the new module_search_path?
if (_Py_path_config.home != NULL) {
- _Py_path_config.stdlib_dir = _PyMem_RawWcsdup(_Py_path_config.home);
+ _Py_path_config.stdlib_dir = _PyMem_DefaultRawWcsdup(_Py_path_config.home);
}
else {
- _Py_path_config.stdlib_dir = _PyMem_RawWcsdup(L"");
+ _Py_path_config.stdlib_dir = _PyMem_DefaultRawWcsdup(L"");
}
- _Py_path_config.module_search_path = _PyMem_RawWcsdup(path);
+ _Py_path_config.module_search_path = _PyMem_DefaultRawWcsdup(path);
_Py_path_config.calculated_module_search_path = NULL;
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
if (_Py_path_config.prefix == NULL
|| _Py_path_config.exec_prefix == NULL
|| _Py_path_config.stdlib_dir == NULL
{
int has_value = home && home[0];
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
- PyMem_RawFree(_Py_path_config.home);
+ _PyMem_DefaultRawFree(_Py_path_config.home);
_Py_path_config.home = NULL;
if (has_value) {
- _Py_path_config.home = _PyMem_RawWcsdup(home);
+ _Py_path_config.home = _PyMem_DefaultRawWcsdup(home);
}
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
if (has_value && _Py_path_config.home == NULL) {
path_out_of_memory(__func__);
}
{
int has_value = program_name && program_name[0];
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
- PyMem_RawFree(_Py_path_config.program_name);
+ _PyMem_DefaultRawFree(_Py_path_config.program_name);
_Py_path_config.program_name = NULL;
if (has_value) {
- _Py_path_config.program_name = _PyMem_RawWcsdup(program_name);
+ _Py_path_config.program_name = _PyMem_DefaultRawWcsdup(program_name);
}
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
if (has_value && _Py_path_config.program_name == NULL) {
path_out_of_memory(__func__);
}
#include "pycore_parking_lot.h" // _PyParkingLot_AfterFork()
#include "pycore_pyerrors.h" // _PyErr_Clear()
#include "pycore_pylifecycle.h" // _PyAST_Fini()
-#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
+#include "pycore_pymem.h" // _PyMem_DebugEnabled()
#include "pycore_pystate.h"
#include "pycore_runtime_init.h" // _PyRuntimeState_INIT
#include "pycore_stackref.h" // Py_STACKREF_DEBUG
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
#include "pycore_pylifecycle.h" // _PyErr_WriteUnraisableDefaultHook()
#include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR
-#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
+#include "pycore_pymem.h" // _PyMem_DefaultRawFree()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_pystats.h" // _Py_PrintSpecializationStats()
#include "pycore_structseq.h" // _PyStructSequence_InitBuiltinWithFlags()
/* To get this to work, we have to initialize the runtime implicitly */
_PyRuntime_Initialize();
- /* Force default allocator, so we can ensure that it also gets used to
+ /* Use the default allocator, so we can ensure that it also gets used to
* destroy the linked list in _clear_preinit_entries.
*/
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
- _Py_PreInitEntry node = PyMem_RawCalloc(1, sizeof(*node));
+ _Py_PreInitEntry node = _PyMem_DefaultRawCalloc(1, sizeof(*node));
if (node != NULL) {
- node->value = _PyMem_RawWcsdup(value);
+ node->value = _PyMem_DefaultRawWcsdup(value);
if (node->value == NULL) {
- PyMem_RawFree(node);
+ _PyMem_DefaultRawFree(node);
node = NULL;
};
};
-
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
return node;
}
_Py_PreInitEntry current = *optionlist;
*optionlist = NULL;
/* Deallocate the nodes and their contents using the default allocator */
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
while (current != NULL) {
_Py_PreInitEntry next = current->next;
- PyMem_RawFree(current->value);
- PyMem_RawFree(current);
+ _PyMem_DefaultRawFree(current->value);
+ _PyMem_DefaultRawFree(current);
current = next;
}
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
}
# This file contains suppressions for the default (with GIL) build.
# reference: https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions
-race:get_allocator_unlocked
-race:set_allocator_unlocked
# https://gist.github.com/mpage/daaf32b39180c1989572957b943eb665
thread:pthread_create
#
# reference: https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions
-## Default build suppresssions
-
-race:get_allocator_unlocked
-race:set_allocator_unlocked
-
## Free-threaded suppressions
race_top:type_modified_unlocked
race_top:write_thread_id
race_top:PyThreadState_Clear
-# Only seen on macOS, sample: https://gist.github.com/aisk/dda53f5d494a4556c35dde1fce03259c
-race_top:set_default_allocator_unlocked
# gh-129068: race on shared range iterators (test_free_threading.test_zip.ZipThreading.test_threading)
race_top:rangeiter_next