}
+/* Read configuration settings from standard locations
+ *
+ * This function doesn't make any changes to the interpreter state - it
+ * merely populates any missing configuration settings. This allows an
+ * embedding application to completely override a config option by
+ * setting it before calling this function, or else modify the default
+ * setting before passing the fully populated config to Py_EndInitialization.
+ *
+ * More advanced selective initialization tricks are possible by calling
+ * this function multiple times with various preconfigured settings.
+ */
+
+_PyInitError
+_PyCoreConfig_Read(_PyCoreConfig *config)
+{
+ if (config->program_name == NULL) {
+#ifdef MS_WINDOWS
+ const wchar_t *program_name = L"python";
+#else
+ const wchar_t *program_name = L"python3";
+#endif
+ config->program_name = _PyMem_RawWcsdup(program_name);
+ if (config->program_name == NULL) {
+ return _Py_INIT_NO_MEMORY();
+ }
+ }
+
+ return _Py_INIT_OK();
+}
+
+
+void
+_PyCoreConfig_Clear(_PyCoreConfig *config)
+{
+#define CLEAR(ATTR) \
+ do { \
+ PyMem_RawFree(ATTR); \
+ ATTR = NULL; \
+ } while (0)
+
+ CLEAR(config->module_search_path_env);
+ CLEAR(config->home);
+ CLEAR(config->program_name);
+#undef CLEAR
+}
+
+
+int
+_PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
+{
+ _PyCoreConfig_Clear(config);
+
+#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
+ COPY_ATTR(ignore_environment);
+ COPY_ATTR(use_hash_seed);
+ COPY_ATTR(hash_seed);
+ COPY_ATTR(_disable_importlib);
+ COPY_ATTR(allocator);
+ COPY_ATTR(dev_mode);
+ COPY_ATTR(faulthandler);
+ COPY_ATTR(tracemalloc);
+ COPY_ATTR(import_time);
+ COPY_ATTR(show_ref_count);
+ COPY_ATTR(show_alloc_count);
+ COPY_ATTR(dump_refs);
+ COPY_ATTR(malloc_stats);
+ COPY_ATTR(utf8_mode);
+#undef COPY_ATTR
+
+#define COPY_STR_ATTR(ATTR) \
+ do { \
+ if (config2->ATTR != NULL) { \
+ config->ATTR = _PyMem_RawWcsdup(config2->ATTR); \
+ if (config->ATTR == NULL) { \
+ return -1; \
+ } \
+ } \
+ } while (0)
+
+ COPY_STR_ATTR(module_search_path_env);
+ COPY_STR_ATTR(home);
+ COPY_STR_ATTR(program_name);
+#undef COPY_STR_ATTR
+ return 0;
+}
+
+
+void
+_PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *config)
+{
+ Py_CLEAR(config->argv);
+ Py_CLEAR(config->module_search_path);
+ Py_CLEAR(config->warnoptions);
+ Py_CLEAR(config->xoptions);
+}
+
+
+static PyObject*
+config_copy_attr(PyObject *obj)
+{
+ if (PyUnicode_Check(obj)) {
+ Py_INCREF(obj);
+ return obj;
+ }
+ else if (PyList_Check(obj)) {
+ return PyList_GetSlice(obj, 0, Py_SIZE(obj));
+ }
+ else if (PyDict_Check(obj)) {
+ /* The dict type is used for xoptions. Make the assumption that keys
+ and values are immutables */
+ return PyDict_Copy(obj);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "cannot copy config attribute of type %.200s",
+ Py_TYPE(obj)->tp_name);
+ return NULL;
+ }
+}
+
+
+int
+_PyMainInterpreterConfig_Copy(_PyMainInterpreterConfig *config,
+ const _PyMainInterpreterConfig *config2)
+{
+ _PyMainInterpreterConfig_Clear(config);
+
+#define COPY_ATTR(ATTR) \
+ do { \
+ if (config2->ATTR != NULL) { \
+ config->ATTR = config_copy_attr(config2->ATTR); \
+ if (config->ATTR == NULL) { \
+ return -1; \
+ } \
+ } \
+ } while (0)
+
+ COPY_ATTR(argv);
+ COPY_ATTR(module_search_path);
+ COPY_ATTR(warnoptions);
+ COPY_ATTR(xoptions);
+#undef COPY_ATTR
+ return 0;
+}
+
+
+
+
static PyObject *
config_create_path_list(const wchar_t *path, wchar_t delim)
{
*/
_PyInitError
-_Py_InitializeCore(const _PyCoreConfig *config)
+_Py_InitializeCore(const _PyCoreConfig *core_config)
{
+ assert(core_config != NULL);
+
PyInterpreterState *interp;
PyThreadState *tstate;
PyObject *bimod, *sysmod, *pstderr;
- _PyCoreConfig core_config = _PyCoreConfig_INIT;
- _PyMainInterpreterConfig preinit_config = _PyMainInterpreterConfig_INIT;
_PyInitError err;
err = _PyRuntime_Initialize();
return err;
}
- if (config != NULL) {
- core_config = *config;
- }
-
- if (_PyMem_SetupAllocators(core_config.allocator) < 0) {
+ if (_PyMem_SetupAllocators(core_config->allocator) < 0) {
return _Py_INIT_USER_ERR("Unknown PYTHONMALLOC allocator");
}
_emit_stderr_warning_for_legacy_locale();
#endif
- err = _Py_HashRandomization_Init(&core_config);
+ err = _Py_HashRandomization_Init(core_config);
if (_Py_INIT_FAILED(err)) {
return err;
}
- if (!core_config.use_hash_seed || core_config.hash_seed) {
+ if (!core_config->use_hash_seed || core_config->hash_seed) {
/* Random or non-zero hash seed */
Py_HashRandomizationFlag = 1;
}
}
interp = PyInterpreterState_New();
- if (interp == NULL)
+ if (interp == NULL) {
return _Py_INIT_ERR("can't make main interpreter");
- interp->core_config = core_config;
- interp->config = preinit_config;
+ }
+
+ if (_PyCoreConfig_Copy(&interp->core_config, core_config) < 0) {
+ return _Py_INIT_ERR("failed to copy core config");
+ }
tstate = PyThreadState_New(interp);
if (tstate == NULL)
return _Py_INIT_OK();
}
-/* Read configuration settings from standard locations
- *
- * This function doesn't make any changes to the interpreter state - it
- * merely populates any missing configuration settings. This allows an
- * embedding application to completely override a config option by
- * setting it before calling this function, or else modify the default
- * setting before passing the fully populated config to Py_EndInitialization.
- *
- * More advanced selective initialization tricks are possible by calling
- * this function multiple times with various preconfigured settings.
- */
-
-_PyInitError
-_PyCoreConfig_Read(_PyCoreConfig *config)
-{
- if (config->program_name == NULL) {
-#ifdef MS_WINDOWS
- const wchar_t *program_name = L"python";
-#else
- const wchar_t *program_name = L"python3";
-#endif
- config->program_name = _PyMem_RawWcsdup(program_name);
- if (config->program_name == NULL) {
- return _Py_INIT_NO_MEMORY();
- }
- }
-
- return _Py_INIT_OK();
-}
-
-void
-_PyCoreConfig_Clear(_PyCoreConfig *config)
-{
-#define CLEAR(ATTR) \
- do { \
- PyMem_RawFree(ATTR); \
- ATTR = NULL; \
- } while (0)
-
- CLEAR(config->module_search_path_env);
- CLEAR(config->home);
- CLEAR(config->program_name);
-#undef CLEAR
-}
-
-
-void
-_PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *config)
-{
- Py_CLEAR(config->argv);
- Py_CLEAR(config->module_search_path);
- Py_CLEAR(config->warnoptions);
- Py_CLEAR(config->xoptions);
-}
-
-
/* Update interpreter state based on supplied configuration settings
*
* After calling this function, most of the restrictions on the interpreter
return _Py_INIT_ERR("failed to get interpreter");
/* Now finish configuring the main interpreter */
- interp->config = *config;
+ if (_PyMainInterpreterConfig_Copy(&interp->config, config) < 0) {
+ return _Py_INIT_ERR("failed to copy main interpreter config");
+ }
if (interp->core_config._disable_importlib) {
/* Special mode for freeze_importlib: run with no import system
}
}
- if (_PySys_EndInit(interp->sysdict) < 0)
+ if (_PySys_EndInit(interp->sysdict) < 0) {
return _Py_INIT_ERR("can't finish initializing sys");
+ }
err = initexternalimport(interp);
if (_Py_INIT_FAILED(err)) {
core_config._disable_importlib = !install_importlib;
config.install_signal_handlers = install_sigs;
- err = _Py_InitializeCore(&core_config);
+ err = _PyCoreConfig_ReadEnv(&core_config);
if (_Py_INIT_FAILED(err)) {
goto done;
}
- err = _PyCoreConfig_ReadEnv(&core_config);
+ err = _Py_InitializeCore(&core_config);
if (_Py_INIT_FAILED(err)) {
goto done;
}
tstate = PyThreadState_GET();
interp = tstate->interp;
- /* Copy the core config to be able to use it even
- after PyInterpreterState_Delete() */
- _PyCoreConfig core_config = interp->core_config;
+ /* Copy the core config, PyInterpreterState_Delete() free
+ the core config memory */
+ int show_ref_count = interp->core_config.show_ref_count;
+ int dump_refs = interp->core_config.dump_refs;
+ int malloc_stats = interp->core_config.malloc_stats;
/* Remaining threads (e.g. daemon threads) will automatically exit
after taking the GIL (in PyEval_RestoreThread()). */
_PyHash_Fini();
#ifdef Py_REF_DEBUG
- if (core_config.show_ref_count) {
+ if (show_ref_count) {
_PyDebug_PrintTotalRefs();
}
#endif
* Alas, a lot of stuff may still be alive now that will be cleaned
* up later.
*/
- if (core_config.dump_refs) {
+ if (dump_refs) {
_Py_PrintReferences(stderr);
}
#endif /* Py_TRACE_REFS */
* An address can be used to find the repr of the object, printed
* above by _Py_PrintReferences.
*/
- if (core_config.dump_refs) {
+ if (dump_refs) {
_Py_PrintReferenceAddresses(stderr);
}
#endif /* Py_TRACE_REFS */
#ifdef WITH_PYMALLOC
- if (core_config.malloc_stats) {
+ if (malloc_stats) {
_PyObject_DebugMallocStats(stderr);
}
#endif
save_tstate = PyThreadState_Swap(tstate);
/* Copy the current interpreter config into the new interpreter */
+ _PyCoreConfig *core_config;
+ _PyMainInterpreterConfig *config;
if (save_tstate != NULL) {
- interp->core_config = save_tstate->interp->core_config;
- interp->config = save_tstate->interp->config;
+ core_config = &save_tstate->interp->core_config;
+ config = &save_tstate->interp->config;
} else {
/* No current thread state, copy from the main interpreter */
PyInterpreterState *main_interp = PyInterpreterState_Main();
- interp->core_config = main_interp->core_config;
- interp->config = main_interp->config;
+ core_config = &main_interp->core_config;
+ config = &main_interp->config;
+ }
+
+ if (_PyCoreConfig_Copy(&interp->core_config, core_config) < 0) {
+ return _Py_INIT_ERR("failed to copy core config");
+ }
+ if (_PyMainInterpreterConfig_Copy(&interp->config, config) < 0) {
+ return _Py_INIT_ERR("failed to copy main interpreter config");
}
err = _PyPathConfig_Init(&interp->core_config);