diff options
| author | shadchin <[email protected]> | 2022-04-18 12:39:32 +0300 |
|---|---|---|
| committer | shadchin <[email protected]> | 2022-04-18 12:39:32 +0300 |
| commit | d4be68e361f4258cf0848fc70018dfe37a2acc24 (patch) | |
| tree | 153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Python/pylifecycle.c | |
| parent | 260c02f5ccf242d9d9b8a873afaf6588c00237d6 (diff) | |
IGNIETFERRO-1816 Update Python 3 from 3.9.12 to 3.10.4
ref:9f96be6d02ee8044fdd6f124b799b270c20ce641
Diffstat (limited to 'contrib/tools/python3/src/Python/pylifecycle.c')
| -rw-r--r-- | contrib/tools/python3/src/Python/pylifecycle.c | 1054 |
1 files changed, 737 insertions, 317 deletions
diff --git a/contrib/tools/python3/src/Python/pylifecycle.c b/contrib/tools/python3/src/Python/pylifecycle.c index 7f591179ac4..0d534fcf685 100644 --- a/contrib/tools/python3/src/Python/pylifecycle.c +++ b/contrib/tools/python3/src/Python/pylifecycle.c @@ -2,13 +2,10 @@ #include "Python.h" -#include "Python-ast.h" -#undef Yield /* undefine macro conflicting with <winbase.h> */ - #include "pycore_ceval.h" // _PyEval_FiniGIL() #include "pycore_context.h" // _PyContext_Init() #include "pycore_fileutils.h" // _Py_ResetForceASCII() -#include "pycore_import.h" // _PyImport_Cleanup() +#include "pycore_import.h" // _PyImport_BootstrapImp() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_object.h" // _PyDebug_PrintTotalRefs() #include "pycore_pathconfig.h" // _PyConfig_WritePathConfig() @@ -18,9 +15,12 @@ #include "pycore_sysmodule.h" // _PySys_ClearAuditHooks() #include "pycore_traceback.h" // _Py_DumpTracebackThreads() -#include "grammar.h" // PyGrammar_RemoveAccelerators() #include <locale.h> // setlocale() +#if defined(__APPLE__) +#include <mach-o/loader.h> +#endif + #ifdef HAVE_SIGNAL_H # include <signal.h> // SIG_IGN #endif @@ -38,6 +38,8 @@ (PyObject_TypeCheck((op), &PyWindowsConsoleIO_Type)) #endif +#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str)) + _Py_IDENTIFIER(flush); _Py_IDENTIFIER(name); @@ -50,19 +52,40 @@ _Py_IDENTIFIER(threading); extern "C" { #endif -extern grammar _PyParser_Grammar; /* From graminit.c */ /* Forward declarations */ static PyStatus add_main_module(PyInterpreterState *interp); static PyStatus init_import_site(void); static PyStatus init_set_builtins_open(void); static PyStatus init_sys_streams(PyThreadState *tstate); -static void call_py_exitfuncs(PyThreadState *tstate); static void wait_for_thread_shutdown(PyThreadState *tstate); static void call_ll_exitfuncs(_PyRuntimeState *runtime); int _Py_UnhandledKeyboardInterrupt = 0; -_PyRuntimeState _PyRuntime = _PyRuntimeState_INIT; + +/* The following places the `_PyRuntime` structure in a location that can be + * found without any external information. This is meant to ease access to the + * interpreter state for various runtime debugging tools, but is *not* an + * officially supported feature */ + +#if defined(MS_WINDOWS) + +#pragma section("PyRuntime", read, write) +__declspec(allocate("PyRuntime")) + +#elif defined(__APPLE__) + +__attribute__(( + section(SEG_DATA ",PyRuntime") +)) + +#endif + +_PyRuntimeState _PyRuntime +#if defined(__linux__) && (defined(__GNUC__) || defined(__clang__)) +__attribute__ ((section (".PyRuntime"))) +#endif += _PyRuntimeState_INIT; static int runtime_initialized = 0; PyStatus @@ -99,14 +122,6 @@ _Py_IsFinalizing(void) int (*_PyOS_mystrnicmp_hack)(const char *, const char *, Py_ssize_t) = \ PyOS_mystrnicmp; /* Python/pystrcmp.o */ -/* PyModule_GetWarningsModule is no longer necessary as of 2.6 -since _warnings is builtin. This API should not be used. */ -PyObject * -PyModule_GetWarningsModule(void) -{ - return PyImport_ImportModule("warnings"); -} - /* APIs to access the initialization flags * @@ -137,59 +152,54 @@ Py_IsInitialized(void) having the lock, but you cannot use multiple threads.) */ - -static PyStatus +static int init_importlib(PyThreadState *tstate, PyObject *sysmod) { - PyObject *importlib; - PyObject *impmod; - PyObject *value; + assert(!_PyErr_Occurred(tstate)); + PyInterpreterState *interp = tstate->interp; int verbose = _PyInterpreterState_GetConfig(interp)->verbose; - /* Import _importlib through its frozen version, _frozen_importlib. */ - if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) { - return _PyStatus_ERR("can't import _frozen_importlib"); - } - else if (verbose) { + // Import _importlib through its frozen version, _frozen_importlib. + if (verbose) { PySys_FormatStderr("import _frozen_importlib # frozen\n"); } - importlib = PyImport_AddModule("_frozen_importlib"); + if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) { + return -1; + } + PyObject *importlib = PyImport_AddModule("_frozen_importlib"); // borrowed if (importlib == NULL) { - return _PyStatus_ERR("couldn't get _frozen_importlib from sys.modules"); + return -1; } - interp->importlib = importlib; - Py_INCREF(interp->importlib); + interp->importlib = Py_NewRef(importlib); - interp->import_func = PyDict_GetItemString(interp->builtins, "__import__"); - if (interp->import_func == NULL) - return _PyStatus_ERR("__import__ not found"); - Py_INCREF(interp->import_func); - - /* Import the _imp module */ - impmod = PyInit__imp(); - if (impmod == NULL) { - return _PyStatus_ERR("can't import _imp"); - } - else if (verbose) { + // Import the _imp module + if (verbose) { PySys_FormatStderr("import _imp # builtin\n"); } - if (_PyImport_SetModuleString("_imp", impmod) < 0) { - return _PyStatus_ERR("can't save _imp to sys.modules"); + PyObject *imp_mod = _PyImport_BootstrapImp(tstate); + if (imp_mod == NULL) { + return -1; + } + if (_PyImport_SetModuleString("_imp", imp_mod) < 0) { + Py_DECREF(imp_mod); + return -1; } - /* Install importlib as the implementation of import */ - value = PyObject_CallMethod(importlib, "_install", "OO", sysmod, impmod); + // Install importlib as the implementation of import + PyObject *value = PyObject_CallMethod(importlib, "_install", + "OO", sysmod, imp_mod); + Py_DECREF(imp_mod); if (value == NULL) { - _PyErr_Print(tstate); - return _PyStatus_ERR("importlib install failed"); + return -1; } Py_DECREF(value); - Py_DECREF(impmod); - return _PyStatus_OK(); + assert(!_PyErr_Occurred(tstate)); + return 0; } + static PyStatus init_importlib_external(PyThreadState *tstate) { @@ -438,6 +448,69 @@ _Py_SetLocaleFromEnv(int category) } +static int +interpreter_update_config(PyThreadState *tstate, int only_update_path_config) +{ + const PyConfig *config = &tstate->interp->config; + + if (!only_update_path_config) { + PyStatus status = _PyConfig_Write(config, tstate->interp->runtime); + if (_PyStatus_EXCEPTION(status)) { + _PyErr_SetFromPyStatus(status); + return -1; + } + } + + if (_Py_IsMainInterpreter(tstate->interp)) { + PyStatus status = _PyConfig_WritePathConfig(config); + if (_PyStatus_EXCEPTION(status)) { + _PyErr_SetFromPyStatus(status); + return -1; + } + } + + // Update the sys module for the new configuration + if (_PySys_UpdateConfig(tstate) < 0) { + return -1; + } + return 0; +} + + +int +_PyInterpreterState_SetConfig(const PyConfig *src_config) +{ + PyThreadState *tstate = PyThreadState_Get(); + int res = -1; + + PyConfig config; + PyConfig_InitPythonConfig(&config); + PyStatus status = _PyConfig_Copy(&config, src_config); + if (_PyStatus_EXCEPTION(status)) { + _PyErr_SetFromPyStatus(status); + goto done; + } + + status = PyConfig_Read(&config); + if (_PyStatus_EXCEPTION(status)) { + _PyErr_SetFromPyStatus(status); + goto done; + } + + status = _PyConfig_Copy(&tstate->interp->config, &config); + if (_PyStatus_EXCEPTION(status)) { + _PyErr_SetFromPyStatus(status); + goto done; + } + + res = interpreter_update_config(tstate, 0); + +done: + PyConfig_Clear(&config); + return res; +} + + /* Global initializations. Can be undone by Py_Finalize(). Don't call this twice without an intervening Py_Finalize() call. @@ -472,7 +545,7 @@ pyinit_core_reconfigure(_PyRuntimeState *runtime, return status; } - status = _PyInterpreterState_SetConfig(interp, config); + status = _PyConfig_Copy(&interp->config, config); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -532,10 +605,10 @@ init_interp_create_gil(PyThreadState *tstate) /* finalize_interp_delete() comment explains why _PyEval_FiniGIL() is only called here. */ - _PyEval_FiniGIL(tstate); + _PyEval_FiniGIL(tstate->interp); /* Auto-thread-state API */ - status = _PyGILState_Init(tstate); + status = _PyGILState_SetTstate(tstate); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -555,12 +628,19 @@ pycore_create_interpreter(_PyRuntimeState *runtime, const PyConfig *config, PyThreadState **tstate_p) { + /* Auto-thread-state API */ + PyStatus status = _PyGILState_Init(runtime); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + PyInterpreterState *interp = PyInterpreterState_New(); if (interp == NULL) { return _PyStatus_ERR("can't make main interpreter"); } + assert(_Py_IsMainInterpreter(interp)); - PyStatus status = _PyInterpreterState_SetConfig(interp, config); + status = _PyConfig_Copy(&interp->config, config); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -582,51 +662,75 @@ pycore_create_interpreter(_PyRuntimeState *runtime, static PyStatus -pycore_init_types(PyThreadState *tstate) +pycore_init_singletons(PyInterpreterState *interp) { PyStatus status; - int is_main_interp = _Py_IsMainInterpreter(tstate); - status = _PyGC_Init(tstate); + if (_PyLong_Init(interp) < 0) { + return _PyStatus_ERR("can't init longs"); + } + + if (_Py_IsMainInterpreter(interp)) { + _PyFloat_Init(); + } + + status = _PyBytes_Init(interp); if (_PyStatus_EXCEPTION(status)) { return status; } + status = _PyUnicode_Init(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyTuple_Init(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + return _PyStatus_OK(); +} + + +static PyStatus +pycore_init_types(PyInterpreterState *interp) +{ + PyStatus status; + int is_main_interp = _Py_IsMainInterpreter(interp); + if (is_main_interp) { + if (_PyStructSequence_Init() < 0) { + return _PyStatus_ERR("can't initialize structseq"); + } + status = _PyTypes_Init(); if (_PyStatus_EXCEPTION(status)) { return status; } - } - - if (!_PyLong_Init(tstate)) { - return _PyStatus_ERR("can't init longs"); - } + if (_PyLong_InitTypes() < 0) { + return _PyStatus_ERR("can't init int type"); + } - if (is_main_interp) { - status = _PyUnicode_Init(); + status = _PyUnicode_InitTypes(); if (_PyStatus_EXCEPTION(status)) { return status; } } - status = _PyExc_Init(); - if (_PyStatus_EXCEPTION(status)) { - return status; - } - if (is_main_interp) { - if (!_PyFloat_Init()) { + if (_PyFloat_InitTypes() < 0) { return _PyStatus_ERR("can't init float"); } + } - if (_PyStructSequence_Init() < 0) { - return _PyStatus_ERR("can't initialize structseq"); - } + status = _PyExc_Init(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; } - status = _PyErr_Init(); + status = _PyErr_InitTypes(); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -644,14 +748,13 @@ pycore_init_types(PyThreadState *tstate) static PyStatus pycore_init_builtins(PyThreadState *tstate) { - assert(!_PyErr_Occurred(tstate)); + PyInterpreterState *interp = tstate->interp; - PyObject *bimod = _PyBuiltin_Init(tstate); + PyObject *bimod = _PyBuiltin_Init(interp); if (bimod == NULL) { goto error; } - PyInterpreterState *interp = tstate->interp; if (_PyImport_FixupBuiltin(bimod, "builtins", interp->modules) < 0) { goto error; } @@ -674,8 +777,15 @@ pycore_init_builtins(PyThreadState *tstate) } Py_DECREF(bimod); - assert(!_PyErr_Occurred(tstate)); + // Get the __import__ function + PyObject *import_func = _PyDict_GetItemStringWithError(interp->builtins, + "__import__"); + if (import_func == NULL) { + goto error; + } + interp->import_func = Py_NewRef(import_func); + assert(!_PyErr_Occurred(tstate)); return _PyStatus_OK(); error: @@ -685,54 +795,38 @@ error: static PyStatus -pycore_init_import_warnings(PyThreadState *tstate, PyObject *sysmod) +pycore_interp_init(PyThreadState *tstate) { - assert(!_PyErr_Occurred(tstate)); + PyInterpreterState *interp = tstate->interp; + PyStatus status; + PyObject *sysmod = NULL; - PyStatus status = _PyImportHooks_Init(tstate); + // Create singletons before the first PyType_Ready() call, since + // PyType_Ready() uses singletons like the Unicode empty string (tp_doc) + // and the empty tuple singletons (tp_bases). + status = pycore_init_singletons(interp); if (_PyStatus_EXCEPTION(status)) { return status; } - const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); - if (_Py_IsMainInterpreter(tstate)) { - /* Initialize _warnings. */ - status = _PyWarnings_InitState(tstate); - if (_PyStatus_EXCEPTION(status)) { - return status; - } - - if (config->_install_importlib) { - status = _PyConfig_WritePathConfig(config); - if (_PyStatus_EXCEPTION(status)) { - return status; - } - } + // The GC must be initialized before the first GC collection. + status = _PyGC_Init(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; } - /* This call sets up builtin and frozen import support */ - if (config->_install_importlib) { - status = init_importlib(tstate, sysmod); - if (_PyStatus_EXCEPTION(status)) { - return status; - } + status = pycore_init_types(interp); + if (_PyStatus_EXCEPTION(status)) { + goto done; } - assert(!_PyErr_Occurred(tstate)); - - return _PyStatus_OK(); -} - - -static PyStatus -pycore_interp_init(PyThreadState *tstate) -{ - PyStatus status; - PyObject *sysmod = NULL; + if (_PyWarnings_InitState(interp) < 0) { + return _PyStatus_ERR("can't initialize warnings"); + } - status = pycore_init_types(tstate); + status = _PyAtExit_Init(interp); if (_PyStatus_EXCEPTION(status)) { - goto done; + return status; } status = _PySys_Create(tstate, &sysmod); @@ -745,7 +839,13 @@ pycore_interp_init(PyThreadState *tstate) goto done; } - status = pycore_init_import_warnings(tstate, sysmod); + const PyConfig *config = _PyInterpreterState_GetConfig(interp); + if (config->_install_importlib) { + /* This call sets up builtin and frozen import support */ + if (init_importlib(tstate, sysmod) < 0) { + return _PyStatus_ERR("failed to initialize importlib"); + } + } done: /* sys.modules['sys'] contains a strong reference to the module */ @@ -919,14 +1019,16 @@ pyinit_core(_PyRuntimeState *runtime, } PyConfig config; - _PyConfig_InitCompatConfig(&config); + PyConfig_InitPythonConfig(&config); status = _PyConfig_Copy(&config, src_config); if (_PyStatus_EXCEPTION(status)) { goto done; } - status = PyConfig_Read(&config); + // Read the configuration, but don't compute the path configuration + // (it is computed in the main init). + status = _PyConfig_Read(&config, 0); if (_PyStatus_EXCEPTION(status)) { goto done; } @@ -951,19 +1053,10 @@ done: configuration. Example of bpo-34008: Py_Main() called after Py_Initialize(). */ static PyStatus -_Py_ReconfigureMainInterpreter(PyThreadState *tstate) +pyinit_main_reconfigure(PyThreadState *tstate) { - const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); - - PyObject *argv = _PyWideStringList_AsList(&config->argv); - if (argv == NULL) { - return _PyStatus_NO_MEMORY(); \ - } - - int res = PyDict_SetItemString(tstate->interp->sysdict, "argv", argv); - Py_DECREF(argv); - if (res < 0) { - return _PyStatus_ERR("fail to set sys.argv"); + if (interpreter_update_config(tstate, 0) < 0) { + return _PyStatus_ERR("fail to reconfigure Python"); } return _PyStatus_OK(); } @@ -972,10 +1065,12 @@ _Py_ReconfigureMainInterpreter(PyThreadState *tstate) static PyStatus init_interp_main(PyThreadState *tstate) { + extern void _PyThread_debug_deprecation(void); + assert(!_PyErr_Occurred(tstate)); PyStatus status; - int is_main_interp = _Py_IsMainInterpreter(tstate); + int is_main_interp = _Py_IsMainInterpreter(tstate->interp); PyInterpreterState *interp = tstate->interp; const PyConfig *config = _PyInterpreterState_GetConfig(interp); @@ -991,14 +1086,14 @@ init_interp_main(PyThreadState *tstate) return _PyStatus_OK(); } - if (is_main_interp) { - if (_PyTime_Init() < 0) { - return _PyStatus_ERR("can't initialize time"); - } + // Compute the path configuration + status = _PyConfig_InitPathConfig(&interp->config, 1); + if (_PyStatus_EXCEPTION(status)) { + return status; } - if (_PySys_InitMain(tstate) < 0) { - return _PyStatus_ERR("can't finish initializing sys"); + if (interpreter_update_config(tstate, 1) < 0) { + return _PyStatus_ERR("failed to update the Python config"); } status = init_importlib_external(tstate); @@ -1073,6 +1168,9 @@ init_interp_main(PyThreadState *tstate) #endif } + // Warn about PYTHONTHREADDEBUG deprecation + _PyThread_debug_deprecation(); + assert(!_PyErr_Occurred(tstate)); return _PyStatus_OK(); @@ -1099,7 +1197,7 @@ pyinit_main(PyThreadState *tstate) } if (interp->runtime->initialized) { - return _Py_ReconfigureMainInterpreter(tstate); + return pyinit_main_reconfigure(tstate); } PyStatus status = init_interp_main(tstate); @@ -1111,19 +1209,6 @@ pyinit_main(PyThreadState *tstate) PyStatus -_Py_InitializeMain(void) -{ - PyStatus status = _PyRuntime_Initialize(); - if (_PyStatus_EXCEPTION(status)) { - return status; - } - _PyRuntimeState *runtime = &_PyRuntime; - PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); - return pyinit_main(tstate); -} - - -PyStatus Py_InitializeFromConfig(const PyConfig *config) { if (config == NULL) { @@ -1190,6 +1275,305 @@ Py_Initialize(void) } +PyStatus +_Py_InitializeMain(void) +{ + PyStatus status = _PyRuntime_Initialize(); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + _PyRuntimeState *runtime = &_PyRuntime; + PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); + return pyinit_main(tstate); +} + + +static void +finalize_modules_delete_special(PyThreadState *tstate, int verbose) +{ + // List of names to clear in sys + static const char * const sys_deletes[] = { + "path", "argv", "ps1", "ps2", + "last_type", "last_value", "last_traceback", + "path_hooks", "path_importer_cache", "meta_path", + "__interactivehook__", + NULL + }; + + static const char * const sys_files[] = { + "stdin", "__stdin__", + "stdout", "__stdout__", + "stderr", "__stderr__", + NULL + }; + + PyInterpreterState *interp = tstate->interp; + if (verbose) { + PySys_WriteStderr("# clear builtins._\n"); + } + if (PyDict_SetItemString(interp->builtins, "_", Py_None) < 0) { + PyErr_WriteUnraisable(NULL); + } + + const char * const *p; + for (p = sys_deletes; *p != NULL; p++) { + if (verbose) { + PySys_WriteStderr("# clear sys.%s\n", *p); + } + if (PyDict_SetItemString(interp->sysdict, *p, Py_None) < 0) { + PyErr_WriteUnraisable(NULL); + } + } + for (p = sys_files; *p != NULL; p+=2) { + const char *name = p[0]; + const char *orig_name = p[1]; + if (verbose) { + PySys_WriteStderr("# restore sys.%s\n", name); + } + PyObject *value = _PyDict_GetItemStringWithError(interp->sysdict, + orig_name); + if (value == NULL) { + if (_PyErr_Occurred(tstate)) { + PyErr_WriteUnraisable(NULL); + } + value = Py_None; + } + if (PyDict_SetItemString(interp->sysdict, name, value) < 0) { + PyErr_WriteUnraisable(NULL); + } + } +} + + +static PyObject* +finalize_remove_modules(PyObject *modules, int verbose) +{ + PyObject *weaklist = PyList_New(0); + if (weaklist == NULL) { + PyErr_WriteUnraisable(NULL); + } + +#define STORE_MODULE_WEAKREF(name, mod) \ + if (weaklist != NULL) { \ + PyObject *wr = PyWeakref_NewRef(mod, NULL); \ + if (wr) { \ + PyObject *tup = PyTuple_Pack(2, name, wr); \ + if (!tup || PyList_Append(weaklist, tup) < 0) { \ + PyErr_WriteUnraisable(NULL); \ + } \ + Py_XDECREF(tup); \ + Py_DECREF(wr); \ + } \ + else { \ + PyErr_WriteUnraisable(NULL); \ + } \ + } + +#define CLEAR_MODULE(name, mod) \ + if (PyModule_Check(mod)) { \ + if (verbose && PyUnicode_Check(name)) { \ + PySys_FormatStderr("# cleanup[2] removing %U\n", name); \ + } \ + STORE_MODULE_WEAKREF(name, mod); \ + if (PyObject_SetItem(modules, name, Py_None) < 0) { \ + PyErr_WriteUnraisable(NULL); \ + } \ + } + + if (PyDict_CheckExact(modules)) { + Py_ssize_t pos = 0; + PyObject *key, *value; + while (PyDict_Next(modules, &pos, &key, &value)) { + CLEAR_MODULE(key, value); + } + } + else { + PyObject *iterator = PyObject_GetIter(modules); + if (iterator == NULL) { + PyErr_WriteUnraisable(NULL); + } + else { + PyObject *key; + while ((key = PyIter_Next(iterator))) { + PyObject *value = PyObject_GetItem(modules, key); + if (value == NULL) { + PyErr_WriteUnraisable(NULL); + continue; + } + CLEAR_MODULE(key, value); + Py_DECREF(value); + Py_DECREF(key); + } + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(NULL); + } + Py_DECREF(iterator); + } + } +#undef CLEAR_MODULE +#undef STORE_MODULE_WEAKREF + + return weaklist; +} + + +static void +finalize_clear_modules_dict(PyObject *modules) +{ + if (PyDict_CheckExact(modules)) { + PyDict_Clear(modules); + } + else { + _Py_IDENTIFIER(clear); + if (_PyObject_CallMethodIdNoArgs(modules, &PyId_clear) == NULL) { + PyErr_WriteUnraisable(NULL); + } + } +} + + +static void +finalize_restore_builtins(PyThreadState *tstate) +{ + PyInterpreterState *interp = tstate->interp; + PyObject *dict = PyDict_Copy(interp->builtins); + if (dict == NULL) { + PyErr_WriteUnraisable(NULL); + } + PyDict_Clear(interp->builtins); + if (PyDict_Update(interp->builtins, interp->builtins_copy)) { + _PyErr_Clear(tstate); + } + Py_XDECREF(dict); +} + + +static void +finalize_modules_clear_weaklist(PyInterpreterState *interp, + PyObject *weaklist, int verbose) +{ + // First clear modules imported later + for (Py_ssize_t i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--) { + PyObject *tup = PyList_GET_ITEM(weaklist, i); + PyObject *name = PyTuple_GET_ITEM(tup, 0); + PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1)); + if (mod == Py_None) { + continue; + } + assert(PyModule_Check(mod)); + PyObject *dict = PyModule_GetDict(mod); + if (dict == interp->builtins || dict == interp->sysdict) { + continue; + } + Py_INCREF(mod); + if (verbose && PyUnicode_Check(name)) { + PySys_FormatStderr("# cleanup[3] wiping %U\n", name); + } + _PyModule_Clear(mod); + Py_DECREF(mod); + } +} + + +static void +finalize_clear_sys_builtins_dict(PyInterpreterState *interp, int verbose) +{ + // Clear sys dict + if (verbose) { + PySys_FormatStderr("# cleanup[3] wiping sys\n"); + } + _PyModule_ClearDict(interp->sysdict); + + // Clear builtins dict + if (verbose) { + PySys_FormatStderr("# cleanup[3] wiping builtins\n"); + } + _PyModule_ClearDict(interp->builtins); +} + + +/* Clear modules, as good as we can */ +static void +finalize_modules(PyThreadState *tstate) +{ + PyInterpreterState *interp = tstate->interp; + PyObject *modules = interp->modules; + if (modules == NULL) { + // Already done + return; + } + int verbose = _PyInterpreterState_GetConfig(interp)->verbose; + + // Delete some special builtins._ and sys attributes first. These are + // common places where user values hide and people complain when their + // destructors fail. Since the modules containing them are + // deleted *last* of all, they would come too late in the normal + // destruction order. Sigh. + // + // XXX Perhaps these precautions are obsolete. Who knows? + finalize_modules_delete_special(tstate, verbose); + + // Remove all modules from sys.modules, hoping that garbage collection + // can reclaim most of them: set all sys.modules values to None. + // + // We prepare a list which will receive (name, weakref) tuples of + // modules when they are removed from sys.modules. The name is used + // for diagnosis messages (in verbose mode), while the weakref helps + // detect those modules which have been held alive. + PyObject *weaklist = finalize_remove_modules(modules, verbose); + + // Clear the modules dict + finalize_clear_modules_dict(modules); + + // Restore the original builtins dict, to ensure that any + // user data gets cleared. + finalize_restore_builtins(tstate); + + // Collect garbage + _PyGC_CollectNoFail(tstate); + + // Dump GC stats before it's too late, since it uses the warnings + // machinery. + _PyGC_DumpShutdownStats(interp); + + if (weaklist != NULL) { + // Now, if there are any modules left alive, clear their globals to + // minimize potential leaks. All C extension modules actually end + // up here, since they are kept alive in the interpreter state. + // + // The special treatment of "builtins" here is because even + // when it's not referenced as a module, its dictionary is + // referenced by almost every module's __builtins__. Since + // deleting a module clears its dictionary (even if there are + // references left to it), we need to delete the "builtins" + // module last. Likewise, we don't delete sys until the very + // end because it is implicitly referenced (e.g. by print). + // + // Since dict is ordered in CPython 3.6+, modules are saved in + // importing order. First clear modules imported later. + finalize_modules_clear_weaklist(interp, weaklist, verbose); + Py_DECREF(weaklist); + } + + // Clear sys and builtins modules dict + finalize_clear_sys_builtins_dict(interp, verbose); + + // Clear module dict copies stored in the interpreter state: + // clear PyInterpreterState.modules_by_index and + // clear PyModuleDef.m_base.m_copy (of extensions not using the multi-phase + // initialization API) + _PyInterpreterState_ClearModules(interp); + + // Clear and delete the modules directory. Actual modules will + // still be there only if imported during the execution of some + // destructor. + Py_SETREF(interp->modules, NULL); + + // Collect garbage once more + _PyGC_CollectNoFail(tstate); +} + + /* Flush stdout and stderr */ static int @@ -1208,6 +1592,7 @@ file_is_closed(PyObject *fobj) return r > 0; } + static int flush_std_files(void) { @@ -1255,56 +1640,37 @@ flush_std_files(void) static void -finalize_interp_types(PyThreadState *tstate, int is_main_interp) +finalize_interp_types(PyInterpreterState *interp) { - if (is_main_interp) { - /* Sundry finalizers */ - _PyAST_Fini(); - _PyFrame_Fini(); - _PyTuple_Fini(); - _PyList_Fini(); - _PySet_Fini(); - _PyBytes_Fini(); - } + _PyExc_Fini(interp); + _PyFrame_Fini(interp); + _PyAsyncGen_Fini(interp); + _PyContext_Fini(interp); + _PyType_Fini(interp); + // Call _PyUnicode_ClearInterned() before _PyDict_Fini() since it uses + // a dict internally. + _PyUnicode_ClearInterned(interp); - _PyLong_Fini(tstate); + _PyDict_Fini(interp); + _PyList_Fini(interp); + _PyTuple_Fini(interp); - if (is_main_interp) { - _PyFloat_Fini(); - _PyDict_Fini(); - _PySlice_Fini(); - } - - _PyWarnings_Fini(tstate->interp); - - if (is_main_interp) { - _Py_HashRandomization_Fini(); - _PyArg_Fini(); - _PyAsyncGen_Fini(); - _PyContext_Fini(); - } + _PySlice_Fini(interp); - /* Cleanup Unicode implementation */ - _PyUnicode_Fini(tstate); - - if (is_main_interp) { - _Py_ClearFileSystemEncoding(); - } + _PyBytes_Fini(interp); + _PyUnicode_Fini(interp); + _PyFloat_Fini(interp); + _PyLong_Fini(interp); } static void finalize_interp_clear(PyThreadState *tstate) { - int is_main_interp = _Py_IsMainInterpreter(tstate); + int is_main_interp = _Py_IsMainInterpreter(tstate->interp); /* Clear interpreter state and all thread states */ - PyInterpreterState_Clear(tstate->interp); - - /* Trigger a GC collection on subinterpreters*/ - if (!is_main_interp) { - _PyGC_CollectNoFail(); - } + _PyInterpreterState_Clear(tstate); /* Clear all loghooks */ /* Both _PySys_Audit function and users still need PyObject, such as tuple. @@ -1313,30 +1679,22 @@ finalize_interp_clear(PyThreadState *tstate) _PySys_ClearAuditHooks(tstate); } - finalize_interp_types(tstate, is_main_interp); - if (is_main_interp) { - /* XXX Still allocated: - - various static ad-hoc pointers to interned strings - - int and float free list blocks - - whatever various modules and libraries allocate - */ - - PyGrammar_RemoveAccelerators(&_PyParser_Grammar); - - _PyExc_Fini(); + _Py_HashRandomization_Fini(); + _PyArg_Fini(); + _Py_ClearFileSystemEncoding(); } - _PyGC_Fini(tstate); + finalize_interp_types(tstate->interp); } static void -finalize_interp_delete(PyThreadState *tstate) +finalize_interp_delete(PyInterpreterState *interp) { - if (_Py_IsMainInterpreter(tstate)) { + if (_Py_IsMainInterpreter(interp)) { /* Cleanup auto-thread-state */ - _PyGILState_Fini(tstate); + _PyGILState_Fini(interp); } /* We can't call _PyEval_FiniGIL() here because destroying the GIL lock can @@ -1345,7 +1703,7 @@ finalize_interp_delete(PyThreadState *tstate) created GIL, which ensures that Py_Initialize / Py_FinalizeEx can be called multiple times. */ - PyInterpreterState_Delete(tstate->interp); + PyInterpreterState_Delete(interp); } @@ -1378,7 +1736,7 @@ Py_FinalizeEx(void) * the threads created via Threading. */ - call_py_exitfuncs(tstate); + _PyAtExit_Call(tstate->interp); /* Copy the core config, PyInterpreterState_Delete() free the core config memory */ @@ -1414,7 +1772,7 @@ Py_FinalizeEx(void) } /* Disable signal handling */ - PyOS_FiniInterrupts(); + _PySignal_Fini(); /* Collect garbage. This may call finalizers; it's nice to call these * before all modules are destroyed. @@ -1428,10 +1786,10 @@ Py_FinalizeEx(void) * XXX but I'm unclear on exactly how that one happens. In any case, * XXX I haven't seen a real-life report of either of these. */ - _PyGC_CollectIfEnabled(); + PyGC_Collect(); /* Destroy all modules */ - _PyImport_Cleanup(tstate); + finalize_modules(tstate); /* Print debug stats if any */ _PyEval_Fini(); @@ -1467,9 +1825,6 @@ Py_FinalizeEx(void) /* Destroy the database used by _PyImport_{Fixup,Find}Extension */ _PyImport_Fini(); - /* Cleanup typeobject.c's internal caches. */ - _PyType_Fini(); - /* unload faulthandler module */ _PyFaulthandler_Fini(); @@ -1494,7 +1849,7 @@ Py_FinalizeEx(void) #endif /* Py_TRACE_REFS */ finalize_interp_clear(tstate); - finalize_interp_delete(tstate); + finalize_interp_delete(tstate->interp); #ifdef Py_TRACE_REFS /* Display addresses (& refcnts) of all objects still alive. @@ -1573,17 +1928,20 @@ new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter) /* Copy the current interpreter config into the new interpreter */ const PyConfig *config; +#ifndef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS if (save_tstate != NULL) { config = _PyInterpreterState_GetConfig(save_tstate->interp); } else +#endif { /* No current thread state, copy from the main interpreter */ PyInterpreterState *main_interp = PyInterpreterState_Main(); config = _PyInterpreterState_GetConfig(main_interp); } - status = _PyInterpreterState_SetConfig(interp, config); + + status = _PyConfig_Copy(&interp->config, config); if (_PyStatus_EXCEPTION(status)) { goto error; } @@ -1666,15 +2024,16 @@ Py_EndInterpreter(PyThreadState *tstate) // Wrap up existing "threading"-module-created, non-daemon threads. wait_for_thread_shutdown(tstate); - call_py_exitfuncs(tstate); + _PyAtExit_Call(tstate->interp); if (tstate != interp->tstate_head || tstate->next != NULL) { Py_FatalError("not the last thread"); } - _PyImport_Cleanup(tstate); + finalize_modules(tstate); + finalize_interp_clear(tstate); - finalize_interp_delete(tstate); + finalize_interp_delete(tstate->interp); } /* Add the __main__ module */ @@ -1695,7 +2054,10 @@ add_main_module(PyInterpreterState *interp) } Py_DECREF(ann_dict); - if (PyDict_GetItemString(d, "__builtins__") == NULL) { + if (_PyDict_GetItemStringWithError(d, "__builtins__") == NULL) { + if (PyErr_Occurred()) { + return _PyStatus_ERR("Failed to test __main__.__builtins__"); + } PyObject *bimod = PyImport_ImportModule("builtins"); if (bimod == NULL) { return _PyStatus_ERR("Failed to retrieve builtins module"); @@ -1712,8 +2074,11 @@ add_main_module(PyInterpreterState *interp) * be set if __main__ gets further initialized later in the startup * process. */ - loader = PyDict_GetItemString(d, "__loader__"); + loader = _PyDict_GetItemStringWithError(d, "__loader__"); if (loader == NULL || loader == Py_None) { + if (PyErr_Occurred()) { + return _PyStatus_ERR("Failed to test __main__.__loader__"); + } PyObject *loader = PyObject_GetAttrString(interp->importlib, "BuiltinImporter"); if (loader == NULL) { @@ -1915,7 +2280,7 @@ error: return NULL; } -/* Set builtins.open to io.OpenWrapper */ +/* Set builtins.open to io.open */ static PyStatus init_set_builtins_open(void) { @@ -1931,7 +2296,7 @@ init_set_builtins_open(void) goto error; } - if (!(wrapper = PyObject_GetAttrString(iomod, "OpenWrapper"))) { + if (!(wrapper = PyObject_GetAttrString(iomod, "open"))) { goto error; } @@ -1953,12 +2318,11 @@ done: } -/* Initialize sys.stdin, stdout, stderr and builtins.open */ +/* Create sys.stdin, sys.stdout and sys.stderr */ static PyStatus init_sys_streams(PyThreadState *tstate) { PyObject *iomod = NULL; - PyObject *m; PyObject *std = NULL; int fd; PyObject * encoding_attr; @@ -1978,18 +2342,6 @@ init_sys_streams(PyThreadState *tstate) } #endif - /* Hack to avoid a nasty recursion issue when Python is invoked - in verbose mode: pre-import the Latin-1 and UTF-8 codecs */ - if ((m = PyImport_ImportModule("encodings.utf_8")) == NULL) { - goto error; - } - Py_DECREF(m); - - if (!(m = PyImport_ImportModule("encodings.latin_1"))) { - goto error; - } - Py_DECREF(m); - if (!(iomod = PyImport_ImportModule("io"))) { goto error; } @@ -2069,8 +2421,7 @@ static void _Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp, PyThreadState *tstate) { - fputc('\n', stderr); - fflush(stderr); + PUTS(fd, "\n"); /* display the current Python stack */ _Py_DumpTracebackThreads(fd, interp, tstate); @@ -2172,30 +2523,31 @@ fatal_output_debug(const char *msg) static void -fatal_error_dump_runtime(FILE *stream, _PyRuntimeState *runtime) +fatal_error_dump_runtime(int fd, _PyRuntimeState *runtime) { - fprintf(stream, "Python runtime state: "); + PUTS(fd, "Python runtime state: "); PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime); if (finalizing) { - fprintf(stream, "finalizing (tstate=%p)", finalizing); + PUTS(fd, "finalizing (tstate=0x"); + _Py_DumpHexadecimal(fd, (uintptr_t)finalizing, sizeof(finalizing) * 2); + PUTS(fd, ")"); } else if (runtime->initialized) { - fprintf(stream, "initialized"); + PUTS(fd, "initialized"); } else if (runtime->core_initialized) { - fprintf(stream, "core initialized"); + PUTS(fd, "core initialized"); } else if (runtime->preinitialized) { - fprintf(stream, "preinitialized"); + PUTS(fd, "preinitialized"); } else if (runtime->preinitializing) { - fprintf(stream, "preinitializing"); + PUTS(fd, "preinitializing"); } else { - fprintf(stream, "unknown"); + PUTS(fd, "unknown"); } - fprintf(stream, "\n"); - fflush(stream); + PUTS(fd, "\n"); } @@ -2214,11 +2566,104 @@ fatal_error_exit(int status) } +// Dump the list of extension modules of sys.modules, excluding stdlib modules +// (sys.stdlib_module_names), into fd file descriptor. +// +// This function is called by a signal handler in faulthandler: avoid memory +// allocations and keep the implementation simple. For example, the list is not +// sorted on purpose. +void +_Py_DumpExtensionModules(int fd, PyInterpreterState *interp) +{ + if (interp == NULL) { + return; + } + PyObject *modules = interp->modules; + if (modules == NULL || !PyDict_Check(modules)) { + return; + } + + Py_ssize_t pos; + PyObject *key, *value; + + // Avoid PyDict_GetItemString() which calls PyUnicode_FromString(), + // memory cannot be allocated on the heap in a signal handler. + // Iterate on the dict instead. + PyObject *stdlib_module_names = NULL; + if (interp->sysdict != NULL) { + pos = 0; + while (PyDict_Next(interp->sysdict, &pos, &key, &value)) { + if (PyUnicode_Check(key) + && PyUnicode_CompareWithASCIIString(key, "stdlib_module_names") == 0) { + stdlib_module_names = value; + break; + } + } + } + // If we failed to get sys.stdlib_module_names or it's not a frozenset, + // don't exclude stdlib modules. + if (stdlib_module_names != NULL && !PyFrozenSet_Check(stdlib_module_names)) { + stdlib_module_names = NULL; + } + + // List extensions + int header = 1; + Py_ssize_t count = 0; + pos = 0; + while (PyDict_Next(modules, &pos, &key, &value)) { + if (!PyUnicode_Check(key)) { + continue; + } + if (!_PyModule_IsExtension(value)) { + continue; + } + // Use the module name from the sys.modules key, + // don't attempt to get the module object name. + if (stdlib_module_names != NULL) { + int is_stdlib_ext = 0; + + Py_ssize_t i = 0; + PyObject *item; + Py_hash_t hash; + while (_PySet_NextEntry(stdlib_module_names, &i, &item, &hash)) { + if (PyUnicode_Check(item) + && PyUnicode_Compare(key, item) == 0) + { + is_stdlib_ext = 1; + break; + } + } + if (is_stdlib_ext) { + // Ignore stdlib extension + continue; + } + } + + if (header) { + PUTS(fd, "\nExtension modules: "); + header = 0; + } + else { + PUTS(fd, ", "); + } + + _Py_DumpASCII(fd, key); + count++; + } + + if (count) { + PUTS(fd, " (total: "); + _Py_DumpDecimal(fd, count); + PUTS(fd, ")"); + PUTS(fd, "\n"); + } +} + + static void _Py_NO_RETURN -fatal_error(FILE *stream, int header, const char *prefix, const char *msg, +fatal_error(int fd, int header, const char *prefix, const char *msg, int status) { - const int fd = fileno(stream); static int reentrant = 0; if (reentrant) { @@ -2229,29 +2674,22 @@ fatal_error(FILE *stream, int header, const char *prefix, const char *msg, reentrant = 1; if (header) { - fprintf(stream, "Fatal Python error: "); + PUTS(fd, "Fatal Python error: "); if (prefix) { - fputs(prefix, stream); - fputs(": ", stream); + PUTS(fd, prefix); + PUTS(fd, ": "); } if (msg) { - fputs(msg, stream); + PUTS(fd, msg); } else { - fprintf(stream, "<message not set>"); + PUTS(fd, "<message not set>"); } - fputs("\n", stream); - fflush(stream); + PUTS(fd, "\n"); } _PyRuntimeState *runtime = &_PyRuntime; - fatal_error_dump_runtime(stream, runtime); - - PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); - PyInterpreterState *interp = NULL; - if (tstate != NULL) { - interp = tstate->interp; - } + fatal_error_dump_runtime(fd, runtime); /* Check if the current thread has a Python thread state and holds the GIL. @@ -2261,8 +2699,17 @@ fatal_error(FILE *stream, int header, const char *prefix, const char *msg, tss_tstate != tstate if the current Python thread does not hold the GIL. */ + PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); + PyInterpreterState *interp = NULL; PyThreadState *tss_tstate = PyGILState_GetThisThreadState(); + if (tstate != NULL) { + interp = tstate->interp; + } + else if (tss_tstate != NULL) { + interp = tss_tstate->interp; + } int has_tstate_and_gil = (tss_tstate != NULL && tss_tstate == tstate); + if (has_tstate_and_gil) { /* If an exception is set, print the exception with its traceback */ if (!_Py_FatalError_PrintExc(tss_tstate)) { @@ -2274,6 +2721,8 @@ fatal_error(FILE *stream, int header, const char *prefix, const char *msg, _Py_FatalError_DumpTracebacks(fd, interp, tss_tstate); } + _Py_DumpExtensionModules(fd, interp); + /* The main purpose of faulthandler is to display the traceback. This function already did its best to display a traceback. Disable faulthandler to prevent writing a second traceback @@ -2299,14 +2748,14 @@ fatal_error(FILE *stream, int header, const char *prefix, const char *msg, void _Py_NO_RETURN Py_FatalError(const char *msg) { - fatal_error(stderr, 1, NULL, msg, -1); + fatal_error(fileno(stderr), 1, NULL, msg, -1); } void _Py_NO_RETURN _Py_FatalErrorFunc(const char *func, const char *msg) { - fatal_error(stderr, 1, func, msg, -1); + fatal_error(fileno(stderr), 1, func, msg, -1); } @@ -2321,12 +2770,12 @@ _Py_FatalErrorFormat(const char *func, const char *format, ...) reentrant = 1; FILE *stream = stderr; - fprintf(stream, "Fatal Python error: "); + const int fd = fileno(stream); + PUTS(fd, "Fatal Python error: "); if (func) { - fputs(func, stream); - fputs(": ", stream); + PUTS(fd, func); + PUTS(fd, ": "); } - fflush(stream); va_list vargs; #ifdef HAVE_STDARG_PROTOTYPES @@ -2340,7 +2789,7 @@ _Py_FatalErrorFormat(const char *func, const char *format, ...) fputs("\n", stream); fflush(stream); - fatal_error(stream, 0, NULL, NULL, -1); + fatal_error(fd, 0, NULL, NULL, -1); } @@ -2351,37 +2800,13 @@ Py_ExitStatusException(PyStatus status) exit(status.exitcode); } else if (_PyStatus_IS_ERROR(status)) { - fatal_error(stderr, 1, status.func, status.err_msg, 1); + fatal_error(fileno(stderr), 1, status.func, status.err_msg, 1); } else { Py_FatalError("Py_ExitStatusException() must not be called on success"); } } -/* Clean up and exit */ - -/* For the atexit module. */ -void _Py_PyAtExit(void (*func)(PyObject *), PyObject *module) -{ - PyInterpreterState *is = _PyInterpreterState_GET(); - - /* Guard against API misuse (see bpo-17852) */ - assert(is->pyexitfunc == NULL || is->pyexitfunc == func); - - is->pyexitfunc = func; - is->pyexitmodule = module; -} - -static void -call_py_exitfuncs(PyThreadState *tstate) -{ - PyInterpreterState *interp = tstate->interp; - if (interp->pyexitfunc == NULL) - return; - - (*interp->pyexitfunc)(interp->pyexitmodule); - _PyErr_Clear(tstate); -} /* Wait until threading._shutdown completes, provided the threading module was imported in the first place. @@ -2446,29 +2871,6 @@ Py_Exit(int sts) } -/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. - * - * All of the code in this function must only use async-signal-safe functions, - * listed at `man 7 signal` or - * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. - * - * If this function is updated, update also _posix_spawn() of subprocess.py. - */ -void -_Py_RestoreSignals(void) -{ -#ifdef SIGPIPE - PyOS_setsig(SIGPIPE, SIG_DFL); -#endif -#ifdef SIGXFZ - PyOS_setsig(SIGXFZ, SIG_DFL); -#endif -#ifdef SIGXFSZ - PyOS_setsig(SIGXFSZ, SIG_DFL); -#endif -} - - /* * The file descriptor fd is considered ``interactive'' if either * a) isatty(fd) is TRUE, or @@ -2488,6 +2890,21 @@ Py_FdIsInteractive(FILE *fp, const char *filename) } +int +_Py_FdIsInteractive(FILE *fp, PyObject *filename) +{ + if (isatty((int)fileno(fp))) { + return 1; + } + if (!Py_InteractiveFlag) { + return 0; + } + return (filename == NULL) || + (PyUnicode_CompareWithASCIIString(filename, "<stdin>") == 0) || + (PyUnicode_CompareWithASCIIString(filename, "???") == 0); +} + + /* Wrappers around sigaction() or signal(). */ PyOS_sighandler_t @@ -2540,7 +2957,10 @@ PyOS_setsig(int sig, PyOS_sighandler_t handler) struct sigaction context, ocontext; context.sa_handler = handler; sigemptyset(&context.sa_mask); - context.sa_flags = 0; + /* Using SA_ONSTACK is friendlier to other C/C++/Golang-VM code that + * extension module or embedding code may use where tiny thread stacks + * are used. https://bugs.python.org/issue43390 */ + context.sa_flags = SA_ONSTACK; if (sigaction(sig, &context, &ocontext) == -1) return SIG_ERR; return ocontext.sa_handler; |
