Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b35be4b

Browse files
authored
bpo-36142: Add _PyPreConfig.allocator (GH-12181)
* Move 'allocator' and 'dev_mode' fields from _PyCoreConfig to _PyPreConfig. * Fix InitConfigTests of test_embed: dev_mode sets allocator to "debug", add a new tests for env vars with dev mode enabled.
1 parent 359a2f3 commit b35be4b

7 files changed

Lines changed: 129 additions & 53 deletions

File tree

Include/cpython/coreconfig.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ typedef struct {
8080
Set by -X utf8 command line option and PYTHONUTF8 environment variable.
8181
If set to -1 (default), inherit Py_UTF8Mode value. */
8282
int utf8_mode;
83+
84+
int dev_mode; /* Development mode. PYTHONDEVMODE, -X dev */
85+
char *allocator; /* Memory allocator: PYTHONMALLOC */
8386
} _PyPreConfig;
8487

8588
#ifdef MS_WINDOWS
@@ -109,9 +112,6 @@ typedef struct {
109112
int use_hash_seed; /* PYTHONHASHSEED=x */
110113
unsigned long hash_seed;
111114

112-
const char *allocator; /* Memory allocator: PYTHONMALLOC */
113-
int dev_mode; /* PYTHONDEVMODE, -X dev */
114-
115115
/* Enable faulthandler?
116116
Set to 1 by -X faulthandler and PYTHONFAULTHANDLER. -1 means unset. */
117117
int faulthandler;

Lib/test/test_embed.py

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -561,30 +561,36 @@ def test_init_from_config(self):
561561
}
562562
self.check_config("init_from_config", config)
563563

564+
INIT_ENV_CONFIG = {
565+
'use_hash_seed': 1,
566+
'hash_seed': 42,
567+
'allocator': 'malloc_debug',
568+
'tracemalloc': 2,
569+
'import_time': 1,
570+
'malloc_stats': 1,
571+
'utf8_mode': 1,
572+
'filesystem_encoding': 'utf-8',
573+
'filesystem_errors': UTF8_MODE_ERRORS,
574+
'inspect': 1,
575+
'optimization_level': 2,
576+
'pycache_prefix': 'env_pycache_prefix',
577+
'write_bytecode': 0,
578+
'verbose': 1,
579+
'buffered_stdio': 0,
580+
'stdio_encoding': 'iso8859-1',
581+
'stdio_errors': 'replace',
582+
'user_site_directory': 0,
583+
'faulthandler': 1,
584+
}
585+
564586
def test_init_env(self):
565-
config = {
566-
'use_hash_seed': 1,
567-
'hash_seed': 42,
568-
'allocator': 'malloc_debug',
569-
'tracemalloc': 2,
570-
'import_time': 1,
571-
'malloc_stats': 1,
572-
'utf8_mode': 1,
573-
'filesystem_encoding': 'utf-8',
574-
'filesystem_errors': self.UTF8_MODE_ERRORS,
575-
'inspect': 1,
576-
'optimization_level': 2,
577-
'pycache_prefix': 'env_pycache_prefix',
578-
'write_bytecode': 0,
579-
'verbose': 1,
580-
'buffered_stdio': 0,
581-
'stdio_encoding': 'iso8859-1',
582-
'stdio_errors': 'replace',
583-
'user_site_directory': 0,
584-
'faulthandler': 1,
585-
'dev_mode': 1,
586-
}
587-
self.check_config("init_env", config)
587+
self.check_config("init_env", self.INIT_ENV_CONFIG)
588+
589+
def test_init_env_dev_mode(self):
590+
config = dict(self.INIT_ENV_CONFIG,
591+
allocator='debug',
592+
dev_mode=1)
593+
self.check_config("init_env_dev_mode", config)
588594

589595
def test_init_dev_mode(self):
590596
config = {

Programs/_testembed.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ static int test_init_from_config(void)
437437
config.hash_seed = 123;
438438

439439
putenv("PYTHONMALLOC=malloc");
440-
config.allocator = "malloc_debug";
440+
config.preconfig.allocator = "malloc_debug";
441441

442442
/* dev_mode=1 is tested in test_init_dev_mode() */
443443

@@ -577,7 +577,6 @@ static void test_init_env_putenvs(void)
577577
putenv("PYTHONPYCACHEPREFIX=env_pycache_prefix");
578578
putenv("PYTHONNOUSERSITE=1");
579579
putenv("PYTHONFAULTHANDLER=1");
580-
putenv("PYTHONDEVMODE=1");
581580
putenv("PYTHONIOENCODING=iso8859-1:replace");
582581
/* FIXME: test PYTHONWARNINGS */
583582
/* FIXME: test PYTHONEXECUTABLE */
@@ -589,6 +588,15 @@ static void test_init_env_putenvs(void)
589588
}
590589

591590

591+
static void test_init_env_dev_mode_putenvs(void)
592+
{
593+
test_init_env_putenvs();
594+
putenv("PYTHONMALLOC=malloc");
595+
putenv("PYTHONFAULTHANDLER=");
596+
putenv("PYTHONDEVMODE=1");
597+
}
598+
599+
592600
static int test_init_env(void)
593601
{
594602
/* Test initialization from environment variables */
@@ -601,6 +609,18 @@ static int test_init_env(void)
601609
}
602610

603611

612+
static int test_init_env_dev_mode(void)
613+
{
614+
/* Test initialization from environment variables */
615+
Py_IgnoreEnvironmentFlag = 0;
616+
test_init_env_dev_mode_putenvs();
617+
_testembed_Py_Initialize();
618+
dump_config();
619+
Py_Finalize();
620+
return 0;
621+
}
622+
623+
604624
static int test_init_isolated(void)
605625
{
606626
/* Test _PyCoreConfig.isolated=1 */
@@ -615,7 +635,7 @@ static int test_init_isolated(void)
615635
/* Use path starting with "./" avoids a search along the PATH */
616636
config.program_name = L"./_testembed";
617637

618-
test_init_env_putenvs();
638+
test_init_env_dev_mode_putenvs();
619639
_PyInitError err = _Py_InitializeFromConfig(&config);
620640
if (_Py_INIT_FAILED(err)) {
621641
_Py_ExitInitError(err);
@@ -631,7 +651,7 @@ static int test_init_dev_mode(void)
631651
_PyCoreConfig config = _PyCoreConfig_INIT;
632652
putenv("PYTHONFAULTHANDLER=");
633653
putenv("PYTHONMALLOC=");
634-
config.dev_mode = 1;
654+
config.preconfig.dev_mode = 1;
635655
config.program_name = L"./_testembed";
636656
_PyInitError err = _Py_InitializeFromConfig(&config);
637657
if (_Py_INIT_FAILED(err)) {
@@ -673,6 +693,7 @@ static struct TestCase TestCases[] = {
673693
{ "init_global_config", test_init_global_config },
674694
{ "init_from_config", test_init_from_config },
675695
{ "init_env", test_init_env },
696+
{ "init_env_dev_mode", test_init_env_dev_mode },
676697
{ "init_dev_mode", test_init_dev_mode },
677698
{ "init_isolated", test_init_isolated },
678699
{ NULL, NULL }

Python/coreconfig.c

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -521,8 +521,6 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
521521
COPY_ATTR(use_hash_seed);
522522
COPY_ATTR(hash_seed);
523523
COPY_ATTR(_install_importlib);
524-
COPY_ATTR(allocator);
525-
COPY_ATTR(dev_mode);
526524
COPY_ATTR(faulthandler);
527525
COPY_ATTR(tracemalloc);
528526
COPY_ATTR(import_time);
@@ -931,10 +929,6 @@ config_read_env_vars(_PyCoreConfig *config)
931929
"PYTHONLEGACYWINDOWSSTDIO");
932930
#endif
933931

934-
if (config->allocator == NULL) {
935-
config->allocator = _PyCoreConfig_GetEnv(config, "PYTHONMALLOC");
936-
}
937-
938932
if (_PyCoreConfig_GetEnv(config, "PYTHONDUMPREFS")) {
939933
config->dump_refs = 1;
940934
}
@@ -1059,11 +1053,6 @@ config_read_complex_options(_PyCoreConfig *config)
10591053
|| config_get_xoption(config, L"importtime")) {
10601054
config->import_time = 1;
10611055
}
1062-
if (config_get_xoption(config, L"dev" ) ||
1063-
_PyCoreConfig_GetEnv(config, "PYTHONDEVMODE"))
1064-
{
1065-
config->dev_mode = 1;
1066-
}
10671056

10681057
_PyInitError err;
10691058
if (config->tracemalloc < 0) {
@@ -1427,13 +1416,10 @@ _PyCoreConfig_Read(_PyCoreConfig *config, const _PyPreConfig *preconfig)
14271416
}
14281417

14291418
/* default values */
1430-
if (config->dev_mode) {
1419+
if (config->preconfig.dev_mode) {
14311420
if (config->faulthandler < 0) {
14321421
config->faulthandler = 1;
14331422
}
1434-
if (config->allocator == NULL) {
1435-
config->allocator = "debug";
1436-
}
14371423
}
14381424
if (config->use_hash_seed < 0) {
14391425
config->use_hash_seed = 0;
@@ -1572,8 +1558,6 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config)
15721558
SET_ITEM_INT(install_signal_handlers);
15731559
SET_ITEM_INT(use_hash_seed);
15741560
SET_ITEM_UINT(hash_seed);
1575-
SET_ITEM_STR(allocator);
1576-
SET_ITEM_INT(dev_mode);
15771561
SET_ITEM_INT(faulthandler);
15781562
SET_ITEM_INT(tracemalloc);
15791563
SET_ITEM_INT(import_time);
@@ -1950,7 +1934,7 @@ config_init_warnoptions(_PyCoreConfig *config, const _PyCmdline *cmdline)
19501934
* the lowest precedence entries first so that later entries override them.
19511935
*/
19521936

1953-
if (config->dev_mode) {
1937+
if (config->preconfig.dev_mode) {
19541938
err = _Py_wstrlist_append(&config->nwarnoption,
19551939
&config->warnoptions,
19561940
L"default");

Python/preconfig.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ precmdline_clear(_PyPreCmdline *cmdline)
125125
void
126126
_PyPreConfig_Clear(_PyPreConfig *config)
127127
{
128+
#define CLEAR(ATTR) \
129+
do { \
130+
PyMem_RawFree(ATTR); \
131+
ATTR = NULL; \
132+
} while (0)
133+
134+
CLEAR(config->allocator);
135+
136+
#undef CLEAR
128137
}
129138

130139

@@ -134,6 +143,15 @@ _PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
134143
_PyPreConfig_Clear(config);
135144

136145
#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
146+
#define COPY_STR_ATTR(ATTR) \
147+
do { \
148+
if (config2->ATTR != NULL) { \
149+
config->ATTR = _PyMem_RawStrdup(config2->ATTR); \
150+
if (config->ATTR == NULL) { \
151+
return -1; \
152+
} \
153+
} \
154+
} while (0)
137155

138156
COPY_ATTR(isolated);
139157
COPY_ATTR(use_environment);
@@ -143,8 +161,11 @@ _PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
143161
COPY_ATTR(legacy_windows_fs_encoding);
144162
#endif
145163
COPY_ATTR(utf8_mode);
164+
COPY_ATTR(dev_mode);
165+
COPY_STR_ATTR(allocator);
146166

147167
#undef COPY_ATTR
168+
#undef COPY_STR_ATTR
148169
return 0;
149170
}
150171

@@ -345,6 +366,7 @@ preconfig_read(_PyPreConfig *config, const _PyPreCmdline *cmdline)
345366
{
346367
_PyPreConfig_GetGlobalConfig(config);
347368

369+
/* isolated and use_environment */
348370
if (config->isolated > 0) {
349371
config->use_environment = 0;
350372
}
@@ -354,6 +376,7 @@ preconfig_read(_PyPreConfig *config, const _PyPreCmdline *cmdline)
354376
config->use_environment = 0;
355377
}
356378

379+
/* legacy_windows_fs_encoding, utf8_mode, coerce_c_locale */
357380
if (config->use_environment) {
358381
#ifdef MS_WINDOWS
359382
_Py_get_env_flag(config, &config->legacy_windows_fs_encoding,
@@ -414,11 +437,43 @@ preconfig_read(_PyPreConfig *config, const _PyPreCmdline *cmdline)
414437
if (config->utf8_mode < 0) {
415438
config->utf8_mode = 0;
416439
}
440+
if (config->coerce_c_locale < 0) {
441+
config->coerce_c_locale = 0;
442+
}
443+
444+
/* dev_mode */
445+
if ((cmdline && _Py_get_xoption(cmdline->nxoption, cmdline->xoptions, L"dev"))
446+
|| _PyPreConfig_GetEnv(config, "PYTHONDEVMODE"))
447+
{
448+
config->dev_mode = 1;
449+
}
450+
if (config->dev_mode < 0) {
451+
config->dev_mode = 0;
452+
}
453+
454+
/* allocator */
455+
if (config->dev_mode && config->allocator == NULL) {
456+
config->allocator = _PyMem_RawStrdup("debug");
457+
if (config->allocator == NULL) {
458+
return _Py_INIT_NO_MEMORY();
459+
}
460+
}
461+
462+
if (config->allocator == NULL) {
463+
const char *allocator = _PyPreConfig_GetEnv(config, "PYTHONMALLOC");
464+
if (allocator) {
465+
config->allocator = _PyMem_RawStrdup(allocator);
466+
if (config->allocator == NULL) {
467+
return _Py_INIT_NO_MEMORY();
468+
}
469+
}
470+
}
417471

418472
assert(config->coerce_c_locale >= 0);
419473
assert(config->utf8_mode >= 0);
420474
assert(config->isolated >= 0);
421475
assert(config->use_environment >= 0);
476+
assert(config->dev_mode >= 0);
422477

423478
return _Py_INIT_OK();
424479
}
@@ -448,6 +503,12 @@ _PyPreConfig_AsDict(const _PyPreConfig *config, PyObject *dict)
448503
} while (0)
449504
#define SET_ITEM_INT(ATTR) \
450505
SET_ITEM(#ATTR, PyLong_FromLong(config->ATTR))
506+
#define FROM_STRING(STR) \
507+
((STR != NULL) ? \
508+
PyUnicode_FromString(STR) \
509+
: (Py_INCREF(Py_None), Py_None))
510+
#define SET_ITEM_STR(ATTR) \
511+
SET_ITEM(#ATTR, FROM_STRING(config->ATTR))
451512

452513
SET_ITEM_INT(isolated);
453514
SET_ITEM_INT(use_environment);
@@ -457,13 +518,17 @@ _PyPreConfig_AsDict(const _PyPreConfig *config, PyObject *dict)
457518
#ifdef MS_WINDOWS
458519
SET_ITEM_INT(legacy_windows_fs_encoding);
459520
#endif
521+
SET_ITEM_INT(dev_mode);
522+
SET_ITEM_STR(allocator);
460523
return 0;
461524

462525
fail:
463526
return -1;
464527

528+
#undef FROM_STRING
465529
#undef SET_ITEM
466530
#undef SET_ITEM_INT
531+
#undef SET_ITEM_STR
467532
}
468533

469534

Python/pylifecycle.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,9 +482,9 @@ _Py_Initialize_ReconfigureCore(PyInterpreterState **interp_p,
482482

483483
/* bpo-34008: For backward compatibility reasons, calling Py_Main() after
484484
Py_Initialize() ignores the new configuration. */
485-
if (core_config->allocator != NULL) {
485+
if (core_config->preconfig.allocator != NULL) {
486486
const char *allocator = _PyMem_GetAllocatorsName();
487-
if (allocator == NULL || strcmp(core_config->allocator, allocator) != 0) {
487+
if (allocator == NULL || strcmp(core_config->preconfig.allocator, allocator) != 0) {
488488
return _Py_INIT_USER_ERR("cannot modify memory allocator "
489489
"after first Py_Initialize()");
490490
}
@@ -521,8 +521,8 @@ pycore_init_runtime(const _PyCoreConfig *core_config)
521521
return err;
522522
}
523523

524-
if (core_config->allocator != NULL) {
525-
if (_PyMem_SetupAllocators(core_config->allocator) < 0) {
524+
if (core_config->preconfig.allocator != NULL) {
525+
if (_PyMem_SetupAllocators(core_config->preconfig.allocator) < 0) {
526526
return _Py_INIT_USER_ERR("Unknown PYTHONMALLOC allocator");
527527
}
528528
}

Python/sysmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2180,7 +2180,7 @@ make_flags(void)
21802180
SetFlag(config->quiet);
21812181
SetFlag(config->use_hash_seed == 0 || config->hash_seed != 0);
21822182
SetFlag(config->preconfig.isolated);
2183-
PyStructSequence_SET_ITEM(seq, pos++, PyBool_FromLong(config->dev_mode));
2183+
PyStructSequence_SET_ITEM(seq, pos++, PyBool_FromLong(config->preconfig.dev_mode));
21842184
SetFlag(config->preconfig.utf8_mode);
21852185
#undef SetFlag
21862186

0 commit comments

Comments
 (0)