Skip to content

Commit d13c63d

Browse files
committed
pymem: remove uses of _PyMem_SetDefaultAllocator during finalization
There is a data race (even with the GIL) between the calls to _PyMem_SetDefaultAllocator and calls to PyMem_RawMalloc from other threads.
1 parent 672e119 commit d13c63d

File tree

8 files changed

+176
-139
lines changed

8 files changed

+176
-139
lines changed

Include/internal/pycore_pymem.h

+6
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ PyAPI_FUNC(int) _PyMem_GetAllocatorName(
9292
PYMEM_ALLOCATOR_NOT_SET does nothing. */
9393
PyAPI_FUNC(int) _PyMem_SetupAllocators(PyMemAllocatorName allocator);
9494

95+
extern void * _PyMem_DefaultRawMalloc(size_t);
96+
extern void * _PyMem_DefaultRawCalloc(size_t, size_t);
97+
extern void * _PyMem_DefaultRawRealloc(void *, size_t);
98+
extern void _PyMem_DefaultRawFree(void *);
99+
extern char * _PyMem_DefaultRawStrdup(const char *);
100+
extern wchar_t * _PyMem_DefaultRawWcsdup(const wchar_t *str);
95101

96102
#ifdef __cplusplus
97103
}

Modules/getpath.c

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#include "pycore_initconfig.h"
77
#include "pycore_fileutils.h"
88
#include "pycore_pathconfig.h"
9-
#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
109
#include <wchar.h>
1110

1211
#ifdef MS_WINDOWS

Objects/obmalloc.c

+76
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,82 @@ _PyMem_RawFree(void *Py_UNUSED(ctx), void *ptr)
7373
free(ptr);
7474
}
7575

76+
/* runtime default raw allocator */
77+
78+
void *
79+
_PyMem_DefaultRawMalloc(size_t size)
80+
{
81+
#ifdef Py_DEBUG
82+
return _PyMem_DebugRawMalloc(&_PyRuntime.allocators.debug.raw, size);
83+
#else
84+
return _PyMem_RawMalloc(NULL, size);
85+
#endif
86+
}
87+
88+
void *
89+
_PyMem_DefaultRawCalloc(size_t nelem, size_t elsize)
90+
{
91+
#ifdef Py_DEBUG
92+
return _PyMem_DebugRawCalloc(&_PyRuntime.allocators.debug.raw, nelem, elsize);
93+
#else
94+
return _PyMem_RawCalloc(NULL, nelem, elsize);
95+
#endif
96+
97+
}
98+
99+
void *
100+
_PyMem_DefaultRawRealloc(void *ptr, size_t size)
101+
{
102+
#ifdef Py_DEBUG
103+
return _PyMem_DebugRawRealloc(&_PyRuntime.allocators.debug.raw, ptr, size);
104+
#else
105+
return _PyMem_RawRealloc(NULL, ptr, size);
106+
#endif
107+
}
108+
109+
void
110+
_PyMem_DefaultRawFree(void *ptr)
111+
{
112+
#ifdef Py_DEBUG
113+
_PyMem_DebugRawFree(&_PyRuntime.allocators.debug.raw, ptr);
114+
#else
115+
_PyMem_RawFree(NULL, ptr);
116+
#endif
117+
}
118+
119+
char *
120+
_PyMem_DefaultRawStrdup(const char *str)
121+
{
122+
assert(str != NULL);
123+
size_t size = strlen(str) + 1;
124+
char *copy = _PyMem_DefaultRawMalloc(size);
125+
if (copy == NULL) {
126+
return NULL;
127+
}
128+
memcpy(copy, str, size);
129+
return copy;
130+
}
131+
132+
wchar_t*
133+
_PyMem_DefaultRawWcsdup(const wchar_t *str)
134+
{
135+
assert(str != NULL);
136+
137+
size_t len = wcslen(str);
138+
if (len > (size_t)PY_SSIZE_T_MAX / sizeof(wchar_t) - 1) {
139+
return NULL;
140+
}
141+
142+
size_t size = (len + 1) * sizeof(wchar_t);
143+
wchar_t *str2 = _PyMem_DefaultRawMalloc(size);
144+
if (str2 == NULL) {
145+
return NULL;
146+
}
147+
148+
memcpy(str2, str, size);
149+
return str2;
150+
}
151+
76152
#define MALLOC_ALLOC {NULL, _PyMem_RawMalloc, _PyMem_RawCalloc, _PyMem_RawRealloc, _PyMem_RawFree}
77153

78154
/* the default object allocator */

Python/import.c

+8-30
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include "pycore_pyerrors.h" // _PyErr_SetString()
1010
#include "pycore_pyhash.h" // _Py_KeyedHash()
1111
#include "pycore_pylifecycle.h"
12-
#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
12+
#include "pycore_pymem.h" // _PyMem_DefaultRawFree()
1313
#include "pycore_pystate.h" // _PyInterpreterState_GET()
1414
#include "pycore_sysmodule.h" // _PySys_Audit()
1515
#include "marshal.h" // PyMarshal_ReadObjectFromString()
@@ -228,30 +228,23 @@ _PyImport_Init(void)
228228
if (_PyRuntime.imports.inittab != NULL) {
229229
return _PyStatus_ERR("global import state already initialized");
230230
}
231-
PyStatus status = _PyStatus_OK();
232231

233232
size_t size;
234233
for (size = 0; PyImport_Inittab[size].name != NULL; size++)
235234
;
236235
size++;
237236

238-
/* Force default raw memory allocator to get a known allocator to be able
237+
/* Use default raw memory allocator to get a known allocator to be able
239238
to release the memory in _PyImport_Fini() */
240-
PyMemAllocatorEx old_alloc;
241-
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
242239

243240
/* Make the copy. */
244-
struct _inittab *copied = PyMem_RawMalloc(size * sizeof(struct _inittab));
241+
struct _inittab *copied = _PyMem_DefaultRawMalloc(size * sizeof(struct _inittab));
245242
if (copied == NULL) {
246-
status = PyStatus_NoMemory();
247-
goto done;
243+
return PyStatus_NoMemory();
248244
}
249245
memcpy(copied, PyImport_Inittab, size * sizeof(struct _inittab));
250246
_PyRuntime.imports.inittab = copied;
251-
252-
done:
253-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
254-
return status;
247+
return _PyStatus_OK();
255248
}
256249

257250
static inline void _extensions_cache_clear(void);
@@ -266,32 +259,22 @@ _PyImport_Fini(void)
266259
}
267260

268261
/* Use the same memory allocator as _PyImport_Init(). */
269-
PyMemAllocatorEx old_alloc;
270-
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
271-
272262
/* Free memory allocated by _PyImport_Init() */
273263
struct _inittab *inittab = _PyRuntime.imports.inittab;
274264
_PyRuntime.imports.inittab = NULL;
275-
PyMem_RawFree(inittab);
276-
277-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
265+
_PyMem_DefaultRawFree(inittab);
278266
}
279267

280268
void
281269
_PyImport_Fini2(void)
282270
{
283271
/* Use the same memory allocator than PyImport_ExtendInittab(). */
284-
PyMemAllocatorEx old_alloc;
285-
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
286-
287272
// Reset PyImport_Inittab
288273
PyImport_Inittab = _PyImport_Inittab;
289274

290275
/* Free memory allocated by PyImport_ExtendInittab() */
291-
PyMem_RawFree(inittab_copy);
276+
_PyMem_DefaultRawFree(inittab_copy);
292277
inittab_copy = NULL;
293-
294-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
295278
}
296279

297280
/* Helper for sys */
@@ -2657,14 +2640,11 @@ PyImport_ExtendInittab(struct _inittab *newtab)
26572640

26582641
/* Force default raw memory allocator to get a known allocator to be able
26592642
to release the memory in _PyImport_Fini2() */
2660-
PyMemAllocatorEx old_alloc;
2661-
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
2662-
26632643
/* Allocate new memory for the combined table */
26642644
p = NULL;
26652645
if (i + n <= SIZE_MAX / sizeof(struct _inittab) - 1) {
26662646
size_t size = sizeof(struct _inittab) * (i + n + 1);
2667-
p = PyMem_RawRealloc(inittab_copy, size);
2647+
p = _PyMem_DefaultRawRealloc(inittab_copy, size);
26682648
}
26692649
if (p == NULL) {
26702650
res = -1;
@@ -2678,9 +2658,7 @@ PyImport_ExtendInittab(struct _inittab *newtab)
26782658
}
26792659
memcpy(p + i, newtab, (n + 1) * sizeof(struct _inittab));
26802660
PyImport_Inittab = inittab_copy = p;
2681-
26822661
done:
2683-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
26842662
return res;
26852663
}
26862664

0 commit comments

Comments
 (0)