Skip to content

Commit b16b4e4

Browse files
authored
bpo-36763: Add PyMemAllocatorName (pythonGH-13387)
* Add PyMemAllocatorName enum * _PyPreConfig.allocator type becomes PyMemAllocatorName, instead of char* * Remove _PyPreConfig_Clear() * Add _PyMem_GetAllocatorName() * Rename _PyMem_GetAllocatorsName() to _PyMem_GetCurrentAllocatorName() * Remove _PyPreConfig_SetAllocator(): just call _PyMem_SetupAllocators() directly, we don't have do reallocate the configuration with the new allocator anymore! * _PyPreConfig_Write() parameter becomes const, as it should be in the first place!
1 parent 80ed353 commit b16b4e4

File tree

12 files changed

+119
-112
lines changed

12 files changed

+119
-112
lines changed

Include/cpython/coreconfig.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ typedef struct {
120120
int utf8_mode;
121121

122122
int dev_mode; /* Development mode. PYTHONDEVMODE, -X dev */
123-
char *allocator; /* Memory allocator: PYTHONMALLOC */
123+
124+
/* Memory allocator: PYTHONMALLOC env var */
125+
PyMemAllocatorName allocator;
124126
} _PyPreConfig;
125127

126128
#ifdef MS_WINDOWS
@@ -137,7 +139,7 @@ typedef struct {
137139
.isolated = -1, \
138140
.use_environment = -1, \
139141
.dev_mode = -1, \
140-
.allocator = NULL}
142+
.allocator = PYMEM_ALLOCATOR_NOT_SET}
141143

142144

143145
/* --- _PyCoreConfig ---------------------------------------------- */

Include/cpython/pymem.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,8 @@ PyAPI_FUNC(void *) PyMem_RawCalloc(size_t nelem, size_t elsize);
1111
PyAPI_FUNC(void *) PyMem_RawRealloc(void *ptr, size_t new_size);
1212
PyAPI_FUNC(void) PyMem_RawFree(void *ptr);
1313

14-
/* Configure the Python memory allocators. Pass NULL to use default
15-
allocators. */
16-
PyAPI_FUNC(int) _PyMem_SetupAllocators(const char *opt);
17-
1814
/* Try to get the allocators name set by _PyMem_SetupAllocators(). */
19-
PyAPI_FUNC(const char*) _PyMem_GetAllocatorsName(void);
15+
PyAPI_FUNC(const char*) _PyMem_GetCurrentAllocatorName(void);
2016

2117
PyAPI_FUNC(void *) PyMem_Calloc(size_t nelem, size_t elsize);
2218

@@ -41,6 +37,19 @@ typedef enum {
4137
PYMEM_DOMAIN_OBJ
4238
} PyMemAllocatorDomain;
4339

40+
typedef enum {
41+
PYMEM_ALLOCATOR_NOT_SET = 0,
42+
PYMEM_ALLOCATOR_DEFAULT = 1,
43+
PYMEM_ALLOCATOR_DEBUG = 2,
44+
PYMEM_ALLOCATOR_MALLOC = 3,
45+
PYMEM_ALLOCATOR_MALLOC_DEBUG = 4,
46+
#ifdef WITH_PYMALLOC
47+
PYMEM_ALLOCATOR_PYMALLOC = 5,
48+
PYMEM_ALLOCATOR_PYMALLOC_DEBUG = 6,
49+
#endif
50+
} PyMemAllocatorName;
51+
52+
4453
typedef struct {
4554
/* user context passed as the first argument to the 4 functions */
4655
void *ctx;

Include/internal/pycore_coreconfig.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,14 @@ PyAPI_FUNC(_PyInitError) _PyPreCmdline_Read(_PyPreCmdline *cmdline,
8888

8989
/* --- _PyPreConfig ----------------------------------------------- */
9090

91-
PyAPI_FUNC(void) _PyPreConfig_Clear(_PyPreConfig *config);
9291
PyAPI_FUNC(int) _PyPreConfig_Copy(_PyPreConfig *config,
9392
const _PyPreConfig *config2);
9493
PyAPI_FUNC(PyObject*) _PyPreConfig_AsDict(const _PyPreConfig *config);
9594
PyAPI_FUNC(void) _PyCoreConfig_GetCoreConfig(_PyPreConfig *config,
9695
const _PyCoreConfig *core_config);
9796
PyAPI_FUNC(_PyInitError) _PyPreConfig_Read(_PyPreConfig *config,
9897
const _PyArgv *args);
99-
PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(_PyPreConfig *config);
98+
PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(const _PyPreConfig *config);
10099

101100

102101
/* --- _PyCoreConfig ---------------------------------------------- */

Include/internal/pycore_pymem.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,15 @@ static inline int _PyMem_IsPtrFreed(void *ptr)
179179
#endif
180180
}
181181

182+
PyAPI_FUNC(int) _PyMem_GetAllocatorName(
183+
const char *name,
184+
PyMemAllocatorName *allocator);
185+
186+
/* Configure the Python memory allocators.
187+
Pass PYMEM_ALLOCATOR_DEFAULT to use default allocators.
188+
PYMEM_ALLOCATOR_NOT_SET does nothing. */
189+
PyAPI_FUNC(int) _PyMem_SetupAllocators(PyMemAllocatorName allocator);
190+
182191
#ifdef __cplusplus
183192
}
184193
#endif

Lib/test/test_embed.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414

1515
MS_WINDOWS = (os.name == 'nt')
16+
PYMEM_ALLOCATOR_NOT_SET = 0
17+
PYMEM_ALLOCATOR_DEBUG = 2
18+
PYMEM_ALLOCATOR_MALLOC = 3
1619

1720

1821
class EmbeddingTestsMixin:
@@ -272,7 +275,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
272275
# Mark config which should be get by get_default_config()
273276
GET_DEFAULT_CONFIG = object()
274277
DEFAULT_PRE_CONFIG = {
275-
'allocator': None,
278+
'allocator': PYMEM_ALLOCATOR_NOT_SET,
276279
'coerce_c_locale': 0,
277280
'coerce_c_locale_warn': 0,
278281
'utf8_mode': 0,
@@ -564,7 +567,7 @@ def test_init_global_config(self):
564567

565568
def test_init_from_config(self):
566569
preconfig = {
567-
'allocator': 'malloc',
570+
'allocator': PYMEM_ALLOCATOR_MALLOC,
568571
'utf8_mode': 1,
569572
}
570573
config = {
@@ -608,7 +611,7 @@ def test_init_from_config(self):
608611
self.check_config("init_from_config", config, preconfig)
609612

610613
INIT_ENV_PRECONFIG = {
611-
'allocator': 'malloc',
614+
'allocator': PYMEM_ALLOCATOR_MALLOC,
612615
}
613616
INIT_ENV_CONFIG = {
614617
'use_hash_seed': 1,
@@ -633,23 +636,23 @@ def test_init_env(self):
633636

634637
def test_init_env_dev_mode(self):
635638
preconfig = dict(self.INIT_ENV_PRECONFIG,
636-
allocator='debug')
639+
allocator=PYMEM_ALLOCATOR_DEBUG)
637640
config = dict(self.INIT_ENV_CONFIG,
638641
dev_mode=1,
639642
warnoptions=['default'])
640643
self.check_config("init_env_dev_mode", config, preconfig)
641644

642645
def test_init_env_dev_mode_alloc(self):
643646
preconfig = dict(self.INIT_ENV_PRECONFIG,
644-
allocator='malloc')
647+
allocator=PYMEM_ALLOCATOR_MALLOC)
645648
config = dict(self.INIT_ENV_CONFIG,
646649
dev_mode=1,
647650
warnoptions=['default'])
648651
self.check_config("init_env_dev_mode_alloc", config, preconfig)
649652

650653
def test_init_dev_mode(self):
651654
preconfig = {
652-
'allocator': 'debug',
655+
'allocator': PYMEM_ALLOCATOR_DEBUG,
653656
}
654657
config = {
655658
'faulthandler': 1,

Modules/_testcapimodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4297,7 +4297,7 @@ pymem_malloc_without_gil(PyObject *self, PyObject *args)
42974297
static PyObject*
42984298
test_pymem_getallocatorsname(PyObject *self, PyObject *args)
42994299
{
4300-
const char *name = _PyMem_GetAllocatorsName();
4300+
const char *name = _PyMem_GetCurrentAllocatorName();
43014301
if (name == NULL) {
43024302
PyErr_SetString(PyExc_RuntimeError, "cannot get allocators name");
43034303
return NULL;

Objects/obmalloc.c

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -268,49 +268,94 @@ _PyMem_SetDefaultAllocator(PyMemAllocatorDomain domain,
268268

269269

270270
int
271-
_PyMem_SetupAllocators(const char *opt)
271+
_PyMem_GetAllocatorName(const char *name, PyMemAllocatorName *allocator)
272272
{
273-
if (opt == NULL || *opt == '\0') {
273+
if (name == NULL || *name == '\0') {
274274
/* PYTHONMALLOC is empty or is not set or ignored (-E/-I command line
275-
options): use default memory allocators */
276-
opt = "default";
275+
nameions): use default memory allocators */
276+
*allocator = PYMEM_ALLOCATOR_DEFAULT;
277277
}
278+
else if (strcmp(name, "default") == 0) {
279+
*allocator = PYMEM_ALLOCATOR_DEFAULT;
280+
}
281+
else if (strcmp(name, "debug") == 0) {
282+
*allocator = PYMEM_ALLOCATOR_DEBUG;
283+
}
284+
#ifdef WITH_PYMALLOC
285+
else if (strcmp(name, "pymalloc") == 0) {
286+
*allocator = PYMEM_ALLOCATOR_PYMALLOC;
287+
}
288+
else if (strcmp(name, "pymalloc_debug") == 0) {
289+
*allocator = PYMEM_ALLOCATOR_PYMALLOC_DEBUG;
290+
}
291+
#endif
292+
else if (strcmp(name, "malloc") == 0) {
293+
*allocator = PYMEM_ALLOCATOR_MALLOC;
294+
}
295+
else if (strcmp(name, "malloc_debug") == 0) {
296+
*allocator = PYMEM_ALLOCATOR_MALLOC_DEBUG;
297+
}
298+
else {
299+
/* unknown allocator */
300+
return -1;
301+
}
302+
return 0;
303+
}
304+
278305

279-
if (strcmp(opt, "default") == 0) {
306+
int
307+
_PyMem_SetupAllocators(PyMemAllocatorName allocator)
308+
{
309+
switch (allocator) {
310+
case PYMEM_ALLOCATOR_NOT_SET:
311+
/* do nothing */
312+
break;
313+
314+
case PYMEM_ALLOCATOR_DEFAULT:
280315
(void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, NULL);
281316
(void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_MEM, NULL);
282317
(void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_OBJ, NULL);
283-
}
284-
else if (strcmp(opt, "debug") == 0) {
318+
break;
319+
320+
case PYMEM_ALLOCATOR_DEBUG:
285321
(void)pymem_set_default_allocator(PYMEM_DOMAIN_RAW, 1, NULL);
286322
(void)pymem_set_default_allocator(PYMEM_DOMAIN_MEM, 1, NULL);
287323
(void)pymem_set_default_allocator(PYMEM_DOMAIN_OBJ, 1, NULL);
288-
}
324+
break;
325+
289326
#ifdef WITH_PYMALLOC
290-
else if (strcmp(opt, "pymalloc") == 0 || strcmp(opt, "pymalloc_debug") == 0) {
327+
case PYMEM_ALLOCATOR_PYMALLOC:
328+
case PYMEM_ALLOCATOR_PYMALLOC_DEBUG:
329+
{
291330
PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC;
292331
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &malloc_alloc);
293332

294333
PyMemAllocatorEx pymalloc = PYMALLOC_ALLOC;
295334
PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &pymalloc);
296335
PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &pymalloc);
297336

298-
if (strcmp(opt, "pymalloc_debug") == 0) {
337+
if (allocator == PYMEM_ALLOCATOR_PYMALLOC_DEBUG) {
299338
PyMem_SetupDebugHooks();
300339
}
340+
break;
301341
}
302342
#endif
303-
else if (strcmp(opt, "malloc") == 0 || strcmp(opt, "malloc_debug") == 0) {
343+
344+
case PYMEM_ALLOCATOR_MALLOC:
345+
case PYMEM_ALLOCATOR_MALLOC_DEBUG:
346+
{
304347
PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC;
305348
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &malloc_alloc);
306349
PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &malloc_alloc);
307350
PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &malloc_alloc);
308351

309-
if (strcmp(opt, "malloc_debug") == 0) {
352+
if (allocator == PYMEM_ALLOCATOR_MALLOC_DEBUG) {
310353
PyMem_SetupDebugHooks();
311354
}
355+
break;
312356
}
313-
else {
357+
358+
default:
314359
/* unknown allocator */
315360
return -1;
316361
}
@@ -326,7 +371,7 @@ pymemallocator_eq(PyMemAllocatorEx *a, PyMemAllocatorEx *b)
326371

327372

328373
const char*
329-
_PyMem_GetAllocatorsName(void)
374+
_PyMem_GetCurrentAllocatorName(void)
330375
{
331376
PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC;
332377
#ifdef WITH_PYMALLOC

Programs/_testembed.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ static int test_init_from_config(void)
379379
_PyPreConfig preconfig = _PyPreConfig_INIT;
380380

381381
putenv("PYTHONMALLOC=malloc_debug");
382-
preconfig.allocator = "malloc";
382+
preconfig.allocator = PYMEM_ALLOCATOR_MALLOC;
383383

384384
putenv("PYTHONUTF8=0");
385385
Py_UTF8Mode = 0;

Python/coreconfig.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,26 +2021,22 @@ core_read_precmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline)
20212021
_PyPreConfig preconfig = _PyPreConfig_INIT;
20222022
if (_PyPreConfig_Copy(&preconfig, &_PyRuntime.preconfig) < 0) {
20232023
err = _Py_INIT_NO_MEMORY();
2024-
goto done;
2024+
return err;
20252025
}
20262026

20272027
_PyCoreConfig_GetCoreConfig(&preconfig, config);
20282028

20292029
err = _PyPreCmdline_Read(precmdline, &preconfig);
20302030
if (_Py_INIT_FAILED(err)) {
2031-
goto done;
2031+
return err;
20322032
}
20332033

20342034
if (_PyPreCmdline_SetCoreConfig(precmdline, config) < 0) {
20352035
err = _Py_INIT_NO_MEMORY();
2036-
goto done;
2036+
return err;
20372037
}
20382038

2039-
err = _Py_INIT_OK();
2040-
2041-
done:
2042-
_PyPreConfig_Clear(&preconfig);
2043-
return err;
2039+
return _Py_INIT_OK();
20442040
}
20452041

20462042

0 commit comments

Comments
 (0)