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.
This commit is contained in:
Victor Stinner 2018-11-16 11:55:35 +01:00 committed by GitHub
parent b65413b497
commit 37cd982df0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 13 deletions

View File

@ -331,10 +331,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
}) })
# main config # main config
UNTESTED_MAIN_CONFIG = (
# FIXME: untested main configuration variables
'module_search_path',
)
COPY_MAIN_CONFIG = ( COPY_MAIN_CONFIG = (
# Copy core config to main config for expected values # Copy core config to main config for expected values
'argv', 'argv',
@ -346,7 +342,8 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'prefix', 'prefix',
'pycache_prefix', 'pycache_prefix',
'warnoptions', 'warnoptions',
# xoptions is created from core_config in check_main_config() # xoptions is created from core_config in check_main_config().
# 'module_search_paths' is copied to 'module_search_path'.
) )
# global config # global config
@ -426,12 +423,10 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
main_config = config['main_config'] main_config = config['main_config']
# main config # main config
for key in self.UNTESTED_MAIN_CONFIG:
del main_config[key]
expected_main = {} expected_main = {}
for key in self.COPY_MAIN_CONFIG: for key in self.COPY_MAIN_CONFIG:
expected_main[key] = core_config[key] expected_main[key] = core_config[key]
expected_main['module_search_path'] = core_config['module_search_paths']
expected_main['xoptions'] = self.main_xoptions(core_config['xoptions']) expected_main['xoptions'] = self.main_xoptions(core_config['xoptions'])
self.assertEqual(main_config, expected_main) self.assertEqual(main_config, expected_main)

View File

@ -836,8 +836,8 @@ _Py_InitializeMainInterpreter(PyInterpreterState *interp,
} }
/* Initialize warnings. */ /* Initialize warnings. */
if (interp->config.warnoptions != NULL && PyObject *warnoptions = PySys_GetObject("warnoptions");
PyList_Size(interp->config.warnoptions) > 0) if (warnoptions != NULL && PyList_Size(warnoptions) > 0)
{ {
PyObject *warnings_module = PyImport_ImportModule("warnings"); PyObject *warnings_module = PyImport_ImportModule("warnings");
if (warnings_module == NULL) { if (warnings_module == NULL) {

View File

@ -2488,7 +2488,20 @@ _PySys_EndInit(PyObject *sysdict, PyInterpreterState *interp)
assert(config->exec_prefix != NULL); assert(config->exec_prefix != NULL);
assert(config->base_exec_prefix != NULL); assert(config->base_exec_prefix != NULL);
SET_SYS_FROM_STRING_BORROW("path", config->module_search_path); #define COPY_LIST(KEY, ATTR) \
do { \
assert(PyList_Check(config->ATTR)); \
PyObject *list = PyList_GetSlice(config->ATTR, \
0, PyList_GET_SIZE(config->ATTR)); \
if (list == NULL) { \
return -1; \
} \
SET_SYS_FROM_STRING_BORROW(KEY, list); \
Py_DECREF(list); \
} while (0)
COPY_LIST("path", module_search_path);
SET_SYS_FROM_STRING_BORROW("executable", config->executable); SET_SYS_FROM_STRING_BORROW("executable", config->executable);
SET_SYS_FROM_STRING_BORROW("prefix", config->prefix); SET_SYS_FROM_STRING_BORROW("prefix", config->prefix);
SET_SYS_FROM_STRING_BORROW("base_prefix", config->base_prefix); SET_SYS_FROM_STRING_BORROW("base_prefix", config->base_prefix);
@ -2505,12 +2518,19 @@ _PySys_EndInit(PyObject *sysdict, PyInterpreterState *interp)
SET_SYS_FROM_STRING_BORROW("argv", config->argv); SET_SYS_FROM_STRING_BORROW("argv", config->argv);
} }
if (config->warnoptions != NULL) { if (config->warnoptions != NULL) {
SET_SYS_FROM_STRING_BORROW("warnoptions", config->warnoptions); COPY_LIST("warnoptions", warnoptions);
} }
if (config->xoptions != NULL) { if (config->xoptions != NULL) {
SET_SYS_FROM_STRING_BORROW("_xoptions", config->xoptions); PyObject *dict = PyDict_Copy(config->xoptions);
if (dict == NULL) {
return -1;
}
SET_SYS_FROM_STRING_BORROW("_xoptions", dict);
Py_DECREF(dict);
} }
#undef COPY_LIST
/* Set flags to their final values */ /* Set flags to their final values */
SET_SYS_FROM_STRING_INT_RESULT("flags", make_flags()); SET_SYS_FROM_STRING_INT_RESULT("flags", make_flags());
/* prevent user from creating new instances */ /* prevent user from creating new instances */