Skip to content

Commit 37cd982

Browse files
authored
bpo-35239: _PySys_EndInit() copies module_search_path (GH-10532)
* The _PySys_EndInit() function now copies the config->module_search_path list, so config is longer modified when sys.path is updated. * config->warnoptions list and config->xoptions dict are also copied * test_embed: InitConfigTests now also tests main_config['module_search_path'] * Fix _Py_InitializeMainInterpreter(): don't use config->warnoptions but sys.warnoptions to decide if the warnings module should be imported at startup.
1 parent b65413b commit 37cd982

File tree

3 files changed

+28
-13
lines changed

3 files changed

+28
-13
lines changed

Lib/test/test_embed.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
331331
})
332332

333333
# main config
334-
UNTESTED_MAIN_CONFIG = (
335-
# FIXME: untested main configuration variables
336-
'module_search_path',
337-
)
338334
COPY_MAIN_CONFIG = (
339335
# Copy core config to main config for expected values
340336
'argv',
@@ -346,7 +342,8 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
346342
'prefix',
347343
'pycache_prefix',
348344
'warnoptions',
349-
# xoptions is created from core_config in check_main_config()
345+
# xoptions is created from core_config in check_main_config().
346+
# 'module_search_paths' is copied to 'module_search_path'.
350347
)
351348

352349
# global config
@@ -426,12 +423,10 @@ def check_main_config(self, config):
426423
main_config = config['main_config']
427424

428425
# main config
429-
for key in self.UNTESTED_MAIN_CONFIG:
430-
del main_config[key]
431-
432426
expected_main = {}
433427
for key in self.COPY_MAIN_CONFIG:
434428
expected_main[key] = core_config[key]
429+
expected_main['module_search_path'] = core_config['module_search_paths']
435430
expected_main['xoptions'] = self.main_xoptions(core_config['xoptions'])
436431
self.assertEqual(main_config, expected_main)
437432

Python/pylifecycle.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -836,8 +836,8 @@ _Py_InitializeMainInterpreter(PyInterpreterState *interp,
836836
}
837837

838838
/* Initialize warnings. */
839-
if (interp->config.warnoptions != NULL &&
840-
PyList_Size(interp->config.warnoptions) > 0)
839+
PyObject *warnoptions = PySys_GetObject("warnoptions");
840+
if (warnoptions != NULL && PyList_Size(warnoptions) > 0)
841841
{
842842
PyObject *warnings_module = PyImport_ImportModule("warnings");
843843
if (warnings_module == NULL) {

Python/sysmodule.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2488,7 +2488,20 @@ _PySys_EndInit(PyObject *sysdict, PyInterpreterState *interp)
24882488
assert(config->exec_prefix != NULL);
24892489
assert(config->base_exec_prefix != NULL);
24902490

2491-
SET_SYS_FROM_STRING_BORROW("path", config->module_search_path);
2491+
#define COPY_LIST(KEY, ATTR) \
2492+
do { \
2493+
assert(PyList_Check(config->ATTR)); \
2494+
PyObject *list = PyList_GetSlice(config->ATTR, \
2495+
0, PyList_GET_SIZE(config->ATTR)); \
2496+
if (list == NULL) { \
2497+
return -1; \
2498+
} \
2499+
SET_SYS_FROM_STRING_BORROW(KEY, list); \
2500+
Py_DECREF(list); \
2501+
} while (0)
2502+
2503+
COPY_LIST("path", module_search_path);
2504+
24922505
SET_SYS_FROM_STRING_BORROW("executable", config->executable);
24932506
SET_SYS_FROM_STRING_BORROW("prefix", config->prefix);
24942507
SET_SYS_FROM_STRING_BORROW("base_prefix", config->base_prefix);
@@ -2505,12 +2518,19 @@ _PySys_EndInit(PyObject *sysdict, PyInterpreterState *interp)
25052518
SET_SYS_FROM_STRING_BORROW("argv", config->argv);
25062519
}
25072520
if (config->warnoptions != NULL) {
2508-
SET_SYS_FROM_STRING_BORROW("warnoptions", config->warnoptions);
2521+
COPY_LIST("warnoptions", warnoptions);
25092522
}
25102523
if (config->xoptions != NULL) {
2511-
SET_SYS_FROM_STRING_BORROW("_xoptions", config->xoptions);
2524+
PyObject *dict = PyDict_Copy(config->xoptions);
2525+
if (dict == NULL) {
2526+
return -1;
2527+
}
2528+
SET_SYS_FROM_STRING_BORROW("_xoptions", dict);
2529+
Py_DECREF(dict);
25122530
}
25132531

2532+
#undef COPY_LIST
2533+
25142534
/* Set flags to their final values */
25152535
SET_SYS_FROM_STRING_INT_RESULT("flags", make_flags());
25162536
/* prevent user from creating new instances */

0 commit comments

Comments
 (0)