diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2017-11-15 23:48:08 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-15 23:48:08 (GMT) |
commit | f7e5b56c37eb859e225e886c79c5d742c567ee95 (patch) | |
tree | 7d722ca38595aaa68e02a1ee1ea53e17a54b0188 /Python | |
parent | 43605e6bfa8d49612df4a38460d063d6ba781906 (diff) | |
download | cpython-f7e5b56c37eb859e225e886c79c5d742c567ee95.zip cpython-f7e5b56c37eb859e225e886c79c5d742c567ee95.tar.gz cpython-f7e5b56c37eb859e225e886c79c5d742c567ee95.tar.bz2 |
bpo-32030: Split Py_Main() into subfunctions (#4399)
* Don't use "Python runtime" anymore to parse command line options or
to get environment variables: pymain_init() is now a strict
separation.
* Use an error message rather than "crashing" directly with
Py_FatalError(). Limit the number of calls to Py_FatalError(). It
prepares the code to handle errors more nicely later.
* Warnings options (-W, PYTHONWARNINGS) and "XOptions" (-X) are now
only added to the sys module once Python core is properly
initialized.
* _PyMain is now the well identified owner of some important strings
like: warnings options, XOptions, and the "program name". The
program name string is now properly freed at exit.
pymain_free() is now responsible to free the "command" string.
* Rename most methods in Modules/main.c to use a "pymain_" prefix to
avoid conflits and ease debug.
* Replace _Py_CommandLineDetails_INIT with memset(0)
* Reorder a lot of code to fix the initialization ordering. For
example, initializing standard streams now comes before parsing
PYTHONWARNINGS.
* Py_Main() now handles errors when adding warnings options and
XOptions.
* Add _PyMem_GetDefaultRawAllocator() private function.
* Cleanup _PyMem_Initialize(): remove useless global constants: move
them into _PyMem_Initialize().
* Call _PyRuntime_Initialize() as soon as possible:
_PyRuntime_Initialize() now returns an error message on failure.
* Add _PyInitError structure and following macros:
* _Py_INIT_OK()
* _Py_INIT_ERR(msg)
* _Py_INIT_USER_ERR(msg): "user" error, don't abort() in that case
* _Py_INIT_FAILED(err)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/bootstrap_hash.c | 19 | ||||
-rw-r--r-- | Python/frozenmain.c | 8 | ||||
-rw-r--r-- | Python/import.c | 33 | ||||
-rw-r--r-- | Python/pylifecycle.c | 394 | ||||
-rw-r--r-- | Python/pystate.c | 16 | ||||
-rw-r--r-- | Python/sysmodule.c | 137 |
6 files changed, 396 insertions, 211 deletions
diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c index 807d602..e667fa9 100644 --- a/Python/bootstrap_hash.c +++ b/Python/bootstrap_hash.c @@ -561,15 +561,16 @@ int Py_ReadHashSeed(char *seed_text, return 0; } -static void +static _PyInitError init_hash_secret(int use_hash_seed, unsigned long hash_seed) { void *secret = &_Py_HashSecret; Py_ssize_t secret_size = sizeof(_Py_HashSecret_t); - if (_Py_HashSecret_Initialized) - return; + if (_Py_HashSecret_Initialized) { + return _Py_INIT_OK(); + } _Py_HashSecret_Initialized = 1; if (use_hash_seed) { @@ -593,12 +594,14 @@ init_hash_secret(int use_hash_seed, pyurandom() is non-blocking mode (blocking=0): see the PEP 524. */ res = pyurandom(secret, secret_size, 0, 0); if (res < 0) { - Py_FatalError("failed to get random numbers to initialize Python"); + return _Py_INIT_ERR("failed to get random numbers " + "to initialize Python"); } } + return _Py_INIT_OK(); } -void +_PyInitError _Py_HashRandomization_Init(_PyCoreConfig *core_config) { char *seed_text; @@ -608,13 +611,13 @@ _Py_HashRandomization_Init(_PyCoreConfig *core_config) if (use_hash_seed < 0) { seed_text = Py_GETENV("PYTHONHASHSEED"); if (Py_ReadHashSeed(seed_text, &use_hash_seed, &hash_seed) < 0) { - Py_FatalError("PYTHONHASHSEED must be \"random\" or an integer " - "in range [0; 4294967295]"); + return _Py_INIT_USER_ERR("PYTHONHASHSEED must be \"random\" " + "or an integer in range [0; 4294967295]"); } core_config->use_hash_seed = use_hash_seed; core_config->hash_seed = hash_seed; } - init_hash_secret(use_hash_seed, hash_seed); + return init_hash_secret(use_hash_seed, hash_seed); } void diff --git a/Python/frozenmain.c b/Python/frozenmain.c index 769b33d..77602d7 100644 --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -2,6 +2,7 @@ /* Python interpreter main program for frozen scripts */ #include "Python.h" +#include "internal/pystate.h" #include <locale.h> #ifdef MS_WINDOWS @@ -15,6 +16,13 @@ extern int PyInitFrozenExtensions(void); int Py_FrozenMain(int argc, char **argv) { + _PyInitError err = _PyRuntime_Initialize(); + if (_Py_INIT_FAILED(err)) { + fprintf(stderr, "Fatal Python error: %s\n", err.msg); + fflush(stderr); + exit(1); + } + char *p; int i, n, sts = 1; int inspect = 0; diff --git a/Python/import.c b/Python/import.c index 950c872..fe60844 100644 --- a/Python/import.c +++ b/Python/import.c @@ -42,19 +42,23 @@ module _imp /* Initialize things */ -void +_PyInitError _PyImport_Init(void) { PyInterpreterState *interp = PyThreadState_Get()->interp; initstr = PyUnicode_InternFromString("__init__"); - if (initstr == NULL) - Py_FatalError("Can't initialize import variables"); + if (initstr == NULL) { + return _Py_INIT_ERR("Can't initialize import variables"); + } + interp->builtins_copy = PyDict_Copy(interp->builtins); - if (interp->builtins_copy == NULL) - Py_FatalError("Can't backup builtins dict"); + if (interp->builtins_copy == NULL) { + return _Py_INIT_ERR("Can't backup builtins dict"); + } + return _Py_INIT_OK(); } -void +_PyInitError _PyImportHooks_Init(void) { PyObject *v, *path_hooks = NULL; @@ -80,15 +84,18 @@ _PyImportHooks_Init(void) goto error; err = PySys_SetObject("path_hooks", path_hooks); if (err) { - error: - PyErr_Print(); - Py_FatalError("initializing sys.meta_path, sys.path_hooks, " - "or path_importer_cache failed"); + goto error; } Py_DECREF(path_hooks); + return _Py_INIT_OK(); + + error: + PyErr_Print(); + return _Py_INIT_ERR("initializing sys.meta_path, sys.path_hooks, " + "or path_importer_cache failed"); } -void +_PyInitError _PyImportZip_Init(void) { PyObject *path_hooks, *zimpimport; @@ -133,11 +140,11 @@ _PyImportZip_Init(void) } } - return; + return _Py_INIT_OK(); error: PyErr_Print(); - Py_FatalError("initializing zipimport failed"); + return _Py_INIT_ERR("initializing zipimport failed"); } /* Locking primitives to prevent parallel imports of the same module diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 8817be1..66cc711 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -53,11 +53,11 @@ extern wchar_t *Py_GetPath(void); extern grammar _PyParser_Grammar; /* From graminit.c */ /* Forward */ -static void initmain(PyInterpreterState *interp); -static int initfsencoding(PyInterpreterState *interp); -static void initsite(void); +static _PyInitError add_main_module(PyInterpreterState *interp); +static _PyInitError initfsencoding(PyInterpreterState *interp); +static _PyInitError initsite(void); static int initstdio(void); -static void initsigs(void); +static _PyInitError initsigs(void); static void call_py_exitfuncs(void); static void wait_for_thread_shutdown(void); static void call_ll_exitfuncs(void); @@ -66,7 +66,7 @@ extern int _PyStructSequence_Init(void); extern void _PyUnicode_Fini(void); extern int _PyLong_Init(void); extern void PyLong_Fini(void); -extern int _PyFaulthandler_Init(void); +extern _PyInitError _PyFaulthandler_Init(void); extern void _PyFaulthandler_Fini(void); extern void _PyHash_Fini(void); extern int _PyTraceMalloc_Init(void); @@ -76,9 +76,9 @@ extern void _Py_ReadyTypes(void); extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *); extern void _PyGILState_Fini(void); -_PyRuntimeState _PyRuntime = {0, 0}; +_PyRuntimeState _PyRuntime = _PyRuntimeState_INIT; -void +_PyInitError _PyRuntime_Initialize(void) { /* XXX We only initialize once in the process, which aligns with @@ -88,10 +88,12 @@ _PyRuntime_Initialize(void) This is because the runtime state is not properly finalized currently. */ static int initialized = 0; - if (initialized) - return; + if (initialized) { + return _Py_INIT_OK(); + } initialized = 1; - _PyRuntimeState_Init(&_PyRuntime); + + return _PyRuntimeState_Init(&_PyRuntime); } void @@ -282,43 +284,44 @@ get_locale_encoding(void) #endif } -static void +/* Return NULL on success, or return an error message on failure */ +static _PyInitError initimport(PyInterpreterState *interp, PyObject *sysmod) { PyObject *importlib; PyObject *impmod; PyObject *value; + _PyInitError err; /* Import _importlib through its frozen version, _frozen_importlib. */ if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) { - Py_FatalError("Py_Initialize: can't import _frozen_importlib"); + return _Py_INIT_ERR("can't import _frozen_importlib"); } else if (Py_VerboseFlag) { PySys_FormatStderr("import _frozen_importlib # frozen\n"); } importlib = PyImport_AddModule("_frozen_importlib"); if (importlib == NULL) { - Py_FatalError("Py_Initialize: couldn't get _frozen_importlib from " - "sys.modules"); + return _Py_INIT_ERR("couldn't get _frozen_importlib from sys.modules"); } interp->importlib = importlib; Py_INCREF(interp->importlib); interp->import_func = PyDict_GetItemString(interp->builtins, "__import__"); if (interp->import_func == NULL) - Py_FatalError("Py_Initialize: __import__ not found"); + return _Py_INIT_ERR("__import__ not found"); Py_INCREF(interp->import_func); /* Import the _imp module */ impmod = PyInit_imp(); if (impmod == NULL) { - Py_FatalError("Py_Initialize: can't import _imp"); + return _Py_INIT_ERR("can't import _imp"); } else if (Py_VerboseFlag) { PySys_FormatStderr("import _imp # builtin\n"); } if (_PyImport_SetModuleString("_imp", impmod) < 0) { - Py_FatalError("Py_Initialize: can't save _imp to sys.modules"); + return _Py_INIT_ERR("can't save _imp to sys.modules"); } /* Install importlib as the implementation of import */ @@ -330,15 +333,21 @@ initimport(PyInterpreterState *interp, PyObject *sysmod) } if (value == NULL) { PyErr_Print(); - Py_FatalError("Py_Initialize: importlib install failed"); + return _Py_INIT_ERR("importlib install failed"); } Py_DECREF(value); Py_DECREF(impmod); - _PyImportZip_Init(); + err = _PyImportZip_Init(); + if (_Py_INIT_FAILED(err)) { + return err; + } + + return _Py_INIT_OK(); } -static void +/* Return NULL on success, or return an error message on failure */ +static _PyInitError initexternalimport(PyInterpreterState *interp) { PyObject *value; @@ -346,9 +355,10 @@ initexternalimport(PyInterpreterState *interp) "_install_external_importers", ""); if (value == NULL) { PyErr_Print(); - Py_FatalError("Py_EndInitialization: external importer setup failed"); + return _Py_INIT_ERR("external importer setup failed"); } Py_DECREF(value); + return _Py_INIT_OK(); } /* Helper functions to better handle the legacy C locale @@ -613,13 +623,16 @@ _Py_SetLocaleFromEnv(int category) * Any code invoked from this function should *not* assume it has access * to the Python C API (unless the API is explicitly listed as being * safe to call without calling Py_Initialize first) + * + * Return NULL on success, or return an error message on failure. */ /* TODO: Progressively move functionality from Py_BeginInitialization to * Py_ReadConfig and Py_EndInitialization */ -void _Py_InitializeCore(const _PyCoreConfig *config) +_PyInitError +_Py_InitializeCore(const _PyCoreConfig *config) { PyInterpreterState *interp; PyThreadState *tstate; @@ -627,18 +640,26 @@ void _Py_InitializeCore(const _PyCoreConfig *config) char *p; _PyCoreConfig core_config = _PyCoreConfig_INIT; _PyMainInterpreterConfig preinit_config = _PyMainInterpreterConfig_INIT; + _PyInitError err; - _PyRuntime_Initialize(); + err = _PyRuntime_Initialize(); + if (_Py_INIT_FAILED(err)) { + return err; + } if (config != NULL) { core_config = *config; } + if (_PyMem_SetupAllocators(core_config.allocator) < 0) { + return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator"); + } + if (_PyRuntime.initialized) { - Py_FatalError("Py_InitializeCore: main interpreter already initialized"); + return _Py_INIT_ERR("main interpreter already initialized"); } if (_PyRuntime.core_initialized) { - Py_FatalError("Py_InitializeCore: runtime core already initialized"); + return _Py_INIT_ERR("runtime core already initialized"); } /* Py_Finalize leaves _Py_Finalizing set in order to help daemon @@ -652,13 +673,6 @@ void _Py_InitializeCore(const _PyCoreConfig *config) */ _PyRuntime.finalizing = NULL; - if (_PyMem_SetupAllocators(core_config.allocator) < 0) { - fprintf(stderr, - "Error in PYTHONMALLOC: unknown allocator \"%s\"!\n", - core_config.allocator); - exit(1); - } - #ifndef MS_WINDOWS /* Set up the LC_CTYPE locale, so we can obtain the locale's charset without having to switch @@ -692,7 +706,11 @@ void _Py_InitializeCore(const _PyCoreConfig *config) set_flag(&Py_LegacyWindowsStdioFlag, p); #endif - _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) { /* Random or non-zero hash seed */ Py_HashRandomizationFlag = 1; @@ -701,13 +719,13 @@ void _Py_InitializeCore(const _PyCoreConfig *config) _PyInterpreterState_Enable(&_PyRuntime); interp = PyInterpreterState_New(); if (interp == NULL) - Py_FatalError("Py_InitializeCore: can't make main interpreter"); + return _Py_INIT_ERR("can't make main interpreter"); interp->core_config = core_config; interp->config = preinit_config; tstate = PyThreadState_New(interp); if (tstate == NULL) - Py_FatalError("Py_InitializeCore: can't make first thread"); + return _Py_INIT_ERR("can't make first thread"); (void) PyThreadState_Swap(tstate); /* We can't call _PyEval_FiniThreads() in Py_FinalizeEx because @@ -722,46 +740,50 @@ void _Py_InitializeCore(const _PyCoreConfig *config) _Py_ReadyTypes(); if (!_PyFrame_Init()) - Py_FatalError("Py_InitializeCore: can't init frames"); + return _Py_INIT_ERR("can't init frames"); if (!_PyLong_Init()) - Py_FatalError("Py_InitializeCore: can't init longs"); + return _Py_INIT_ERR("can't init longs"); if (!PyByteArray_Init()) - Py_FatalError("Py_InitializeCore: can't init bytearray"); + return _Py_INIT_ERR("can't init bytearray"); if (!_PyFloat_Init()) - Py_FatalError("Py_InitializeCore: can't init float"); + return _Py_INIT_ERR("can't init float"); PyObject *modules = PyDict_New(); if (modules == NULL) - Py_FatalError("Py_InitializeCore: can't make modules dictionary"); + return _Py_INIT_ERR("can't make modules dictionary"); interp->modules = modules; - sysmod = _PySys_BeginInit(); - if (sysmod == NULL) - Py_FatalError("Py_InitializeCore: can't initialize sys"); + err = _PySys_BeginInit(&sysmod); + if (_Py_INIT_FAILED(err)) { + return err; + } + interp->sysdict = PyModule_GetDict(sysmod); - if (interp->sysdict == NULL) - Py_FatalError("Py_InitializeCore: can't initialize sys dict"); + if (interp->sysdict == NULL) { + return _Py_INIT_ERR("can't initialize sys dict"); + } + Py_INCREF(interp->sysdict); PyDict_SetItemString(interp->sysdict, "modules", modules); _PyImport_FixupBuiltin(sysmod, "sys", modules); /* Init Unicode implementation; relies on the codec registry */ if (_PyUnicode_Init() < 0) - Py_FatalError("Py_InitializeCore: can't initialize unicode"); + return _Py_INIT_ERR("can't initialize unicode"); if (_PyStructSequence_Init() < 0) - Py_FatalError("Py_InitializeCore: can't initialize structseq"); + return _Py_INIT_ERR("can't initialize structseq"); bimod = _PyBuiltin_Init(); if (bimod == NULL) - Py_FatalError("Py_InitializeCore: can't initialize builtins modules"); + return _Py_INIT_ERR("can't initialize builtins modules"); _PyImport_FixupBuiltin(bimod, "builtins", modules); interp->builtins = PyModule_GetDict(bimod); if (interp->builtins == NULL) - Py_FatalError("Py_InitializeCore: can't initialize builtins dict"); + return _Py_INIT_ERR("can't initialize builtins dict"); Py_INCREF(interp->builtins); /* initialize builtin exceptions */ @@ -771,25 +793,35 @@ void _Py_InitializeCore(const _PyCoreConfig *config) infrastructure for the io module in place. */ pstderr = PyFile_NewStdPrinter(fileno(stderr)); if (pstderr == NULL) - Py_FatalError("Py_InitializeCore: can't set preliminary stderr"); + return _Py_INIT_ERR("can't set preliminary stderr"); _PySys_SetObjectId(&PyId_stderr, pstderr); PySys_SetObject("__stderr__", pstderr); Py_DECREF(pstderr); - _PyImport_Init(); + err = _PyImport_Init(); + if (_Py_INIT_FAILED(err)) { + return err; + } - _PyImportHooks_Init(); + err = _PyImportHooks_Init(); + if (_Py_INIT_FAILED(err)) { + return err; + } /* Initialize _warnings. */ _PyWarnings_Init(); /* This call sets up builtin and frozen import support */ if (!interp->core_config._disable_importlib) { - initimport(interp, sysmod); + err = initimport(interp, sysmod); + if (_Py_INIT_FAILED(err)) { + return err; + } } /* Only when we get here is the runtime core fully initialized */ _PyRuntime.core_initialized = 1; + return _Py_INIT_OK(); } /* Read configuration settings from standard locations @@ -802,16 +834,18 @@ void _Py_InitializeCore(const _PyCoreConfig *config) * * More advanced selective initialization tricks are possible by calling * this function multiple times with various preconfigured settings. + * + * Return NULL on success, or return an error message on failure. */ -int _Py_ReadMainInterpreterConfig(_PyMainInterpreterConfig *config) +_PyInitError +_Py_ReadMainInterpreterConfig(_PyMainInterpreterConfig *config) { /* Signal handlers are installed by default */ if (config->install_signal_handlers < 0) { config->install_signal_handlers = 1; } - - return 0; + return _Py_INIT_OK(); } /* Update interpreter state based on supplied configuration settings @@ -824,26 +858,30 @@ int _Py_ReadMainInterpreterConfig(_PyMainInterpreterConfig *config) * initialized or without a valid current thread state is a fatal error. * Other errors should be reported as normal Python exceptions with a * non-zero return code. + * + * Return NULL on success, or return an error message on failure. */ -int _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config) +_PyInitError +_Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config) { PyInterpreterState *interp; PyThreadState *tstate; + _PyInitError err; if (!_PyRuntime.core_initialized) { - Py_FatalError("Py_InitializeMainInterpreter: runtime core not initialized"); + return _Py_INIT_ERR("runtime core not initialized"); } if (_PyRuntime.initialized) { - Py_FatalError("Py_InitializeMainInterpreter: main interpreter already initialized"); + return _Py_INIT_ERR("main interpreter already initialized"); } /* Get current thread state and interpreter pointer */ tstate = PyThreadState_GET(); if (!tstate) - Py_FatalError("Py_InitializeMainInterpreter: failed to read thread state"); + return _Py_INIT_ERR("failed to read thread state"); interp = tstate->interp; if (!interp) - Py_FatalError("Py_InitializeMainInterpreter: failed to get interpreter"); + return _Py_INIT_ERR("failed to get interpreter"); /* Now finish configuring the main interpreter */ interp->config = *config; @@ -855,12 +893,12 @@ int _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config) * or pure Python code in the standard library won't work. */ _PyRuntime.initialized = 1; - return 0; + return _Py_INIT_OK(); } /* TODO: Report exceptions rather than fatal errors below here */ if (_PyTime_Init() < 0) - Py_FatalError("Py_InitializeMainInterpreter: can't initialize time"); + return _Py_INIT_ERR("can't initialize time"); /* Finish setting up the sys module and import system */ /* GetPath may initialize state that _PySys_EndInit locks @@ -868,26 +906,40 @@ int _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config) /* TODO: Call Py_GetPath() in Py_ReadConfig, rather than here */ PySys_SetPath(Py_GetPath()); if (_PySys_EndInit(interp->sysdict) < 0) - Py_FatalError("Py_InitializeMainInterpreter: can't finish initializing sys"); - initexternalimport(interp); + return _Py_INIT_ERR("can't finish initializing sys"); + err = initexternalimport(interp); + if (_Py_INIT_FAILED(err)) { + return err; + } /* initialize the faulthandler module */ - if (_PyFaulthandler_Init()) - Py_FatalError("Py_InitializeMainInterpreter: can't initialize faulthandler"); + err = _PyFaulthandler_Init(); + if (_Py_INIT_FAILED(err)) { + return err; + } - if (initfsencoding(interp) < 0) - Py_FatalError("Py_InitializeMainInterpreter: unable to load the file system codec"); + err = initfsencoding(interp); + if (_Py_INIT_FAILED(err)) { + return err; + } - if (config->install_signal_handlers) - initsigs(); /* Signal handling stuff, including initintr() */ + if (config->install_signal_handlers) { + err = initsigs(); /* Signal handling stuff, including initintr() */ + if (_Py_INIT_FAILED(err)) { + return err; + } + } if (_PyTraceMalloc_Init() < 0) - Py_FatalError("Py_InitializeMainInterpreter: can't initialize tracemalloc"); + return _Py_INIT_ERR("can't initialize tracemalloc"); - initmain(interp); /* Module __main__ */ - if (initstdio() < 0) - Py_FatalError( - "Py_InitializeMainInterpreter: can't initialize sys standard streams"); + err = add_main_module(interp); + if (_Py_INIT_FAILED(err)) { + return err; + } + if (initstdio() < 0) { + return _Py_INIT_ERR("can't initialize sys standard streams"); + } /* Initialize warnings. */ if (PySys_HasWarnOptions()) { @@ -901,37 +953,57 @@ int _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config) _PyRuntime.initialized = 1; - if (!Py_NoSiteFlag) - initsite(); /* Module site */ + if (!Py_NoSiteFlag) { + err = initsite(); /* Module site */ + if (_Py_INIT_FAILED(err)) { + return err; + } + } - return 0; + return _Py_INIT_OK(); } #undef _INIT_DEBUG_PRINT -void +_PyInitError _Py_InitializeEx_Private(int install_sigs, int install_importlib) { _PyCoreConfig core_config = _PyCoreConfig_INIT; _PyMainInterpreterConfig config = _PyMainInterpreterConfig_INIT; + _PyInitError err; /* TODO: Moar config options! */ core_config.ignore_environment = Py_IgnoreEnvironmentFlag; core_config._disable_importlib = !install_importlib; config.install_signal_handlers = install_sigs; - _Py_InitializeCore(&core_config); + + err = _Py_InitializeCore(&core_config); + if (_Py_INIT_FAILED(err)) { + return err; + } + /* TODO: Print any exceptions raised by these operations */ - if (_Py_ReadMainInterpreterConfig(&config)) - Py_FatalError("Py_Initialize: Py_ReadMainInterpreterConfig failed"); - if (_Py_InitializeMainInterpreter(&config)) - Py_FatalError("Py_Initialize: Py_InitializeMainInterpreter failed"); + err = _Py_ReadMainInterpreterConfig(&config); + if (_Py_INIT_FAILED(err)) { + return err; + } + + err = _Py_InitializeMainInterpreter(&config); + if (_Py_INIT_FAILED(err)) { + return err; + } + + return _Py_INIT_OK(); } void Py_InitializeEx(int install_sigs) { - _Py_InitializeEx_Private(install_sigs, 1); + _PyInitError err = _Py_InitializeEx_Private(install_sigs, 1); + if (_Py_INIT_FAILED(err)) { + _Py_FatalInitError(err); + } } void @@ -1236,6 +1308,7 @@ Py_NewInterpreter(void) PyInterpreterState *interp; PyThreadState *tstate, *save_tstate; PyObject *bimod, *sysmod; + _PyInitError err = _Py_INIT_OK(); if (!_PyRuntime.initialized) Py_FatalError("Py_NewInterpreter: call Py_Initialize first"); @@ -1308,25 +1381,50 @@ Py_NewInterpreter(void) PySys_SetObject("__stderr__", pstderr); Py_DECREF(pstderr); - _PyImportHooks_Init(); + err = _PyImportHooks_Init(); + if (_Py_INIT_FAILED(err)) { + goto init_failed; + } - initimport(interp, sysmod); - initexternalimport(interp); + err = initimport(interp, sysmod); + if (_Py_INIT_FAILED(err)) { + goto init_failed; + } - if (initfsencoding(interp) < 0) - goto handle_error; + err = initexternalimport(interp); + if (_Py_INIT_FAILED(err)) { + goto init_failed; + } - if (initstdio() < 0) - Py_FatalError( - "Py_NewInterpreter: can't initialize sys standard streams"); - initmain(interp); - if (!Py_NoSiteFlag) - initsite(); + err = initfsencoding(interp); + if (_Py_INIT_FAILED(err)) { + goto init_failed; + } + + if (initstdio() < 0) { + err = _Py_INIT_ERR("can't initialize sys standard streams"); + goto init_failed; + } + + err = add_main_module(interp); + if (_Py_INIT_FAILED(err)) { + goto init_failed; + } + + if (!Py_NoSiteFlag) { + err = initsite(); + if (_Py_INIT_FAILED(err)) { + goto init_failed; + } + } } if (!PyErr_Occurred()) return tstate; +init_failed: + _Py_FatalInitError(err); + handle_error: /* Oops, it didn't work. Undo it all. */ @@ -1417,32 +1515,35 @@ Py_GetPythonHome(void) return home; } -/* Create __main__ module */ +/* Add the __main__ module */ -static void -initmain(PyInterpreterState *interp) +static _PyInitError +add_main_module(PyInterpreterState *interp) { PyObject *m, *d, *loader, *ann_dict; m = PyImport_AddModule("__main__"); if (m == NULL) - Py_FatalError("can't create __main__ module"); + return _Py_INIT_ERR("can't create __main__ module"); + d = PyModule_GetDict(m); ann_dict = PyDict_New(); if ((ann_dict == NULL) || (PyDict_SetItemString(d, "__annotations__", ann_dict) < 0)) { - Py_FatalError("Failed to initialize __main__.__annotations__"); + return _Py_INIT_ERR("Failed to initialize __main__.__annotations__"); } Py_DECREF(ann_dict); + if (PyDict_GetItemString(d, "__builtins__") == NULL) { PyObject *bimod = PyImport_ImportModule("builtins"); if (bimod == NULL) { - Py_FatalError("Failed to retrieve builtins module"); + return _Py_INIT_ERR("Failed to retrieve builtins module"); } if (PyDict_SetItemString(d, "__builtins__", bimod) < 0) { - Py_FatalError("Failed to initialize __main__.__builtins__"); + return _Py_INIT_ERR("Failed to initialize __main__.__builtins__"); } Py_DECREF(bimod); } + /* Main is a little special - imp.is_builtin("__main__") will return * False, but BuiltinImporter is still the most appropriate initial * setting for its __loader__ attribute. A more suitable value will @@ -1454,41 +1555,40 @@ initmain(PyInterpreterState *interp) PyObject *loader = PyObject_GetAttrString(interp->importlib, "BuiltinImporter"); if (loader == NULL) { - Py_FatalError("Failed to retrieve BuiltinImporter"); + return _Py_INIT_ERR("Failed to retrieve BuiltinImporter"); } if (PyDict_SetItemString(d, "__loader__", loader) < 0) { - Py_FatalError("Failed to initialize __main__.__loader__"); + return _Py_INIT_ERR("Failed to initialize __main__.__loader__"); } Py_DECREF(loader); } + return _Py_INIT_OK(); } -static int +static _PyInitError initfsencoding(PyInterpreterState *interp) { PyObject *codec; #ifdef MS_WINDOWS - if (Py_LegacyWindowsFSEncodingFlag) - { + if (Py_LegacyWindowsFSEncodingFlag) { Py_FileSystemDefaultEncoding = "mbcs"; Py_FileSystemDefaultEncodeErrors = "replace"; } - else - { + else { Py_FileSystemDefaultEncoding = "utf-8"; Py_FileSystemDefaultEncodeErrors = "surrogatepass"; } #else - if (Py_FileSystemDefaultEncoding == NULL) - { + if (Py_FileSystemDefaultEncoding == NULL) { Py_FileSystemDefaultEncoding = get_locale_encoding(); - if (Py_FileSystemDefaultEncoding == NULL) - Py_FatalError("Py_Initialize: Unable to get the locale encoding"); + if (Py_FileSystemDefaultEncoding == NULL) { + return _Py_INIT_ERR("Unable to get the locale encoding"); + } Py_HasFileSystemDefaultEncoding = 0; interp->fscodec_initialized = 1; - return 0; + return _Py_INIT_OK(); } #endif @@ -1498,29 +1598,25 @@ initfsencoding(PyInterpreterState *interp) /* Such error can only occurs in critical situations: no more * memory, import a module of the standard library failed, * etc. */ - return -1; + return _Py_INIT_ERR("unable to load the file system codec"); } Py_DECREF(codec); interp->fscodec_initialized = 1; - return 0; + return _Py_INIT_OK(); } /* Import the site module (not into __main__ though) */ -static void +static _PyInitError initsite(void) { PyObject *m; m = PyImport_ImportModule("site"); if (m == NULL) { - fprintf(stderr, "Failed to import the site module\n"); - PyErr_Print(); - Py_Finalize(); - exit(1); - } - else { - Py_DECREF(m); + return _Py_INIT_USER_ERR("Failed to import the site module"); } + Py_DECREF(m); + return _Py_INIT_OK(); } /* Check if a file descriptor is valid or not. @@ -1926,8 +2022,8 @@ fatal_output_debug(const char *msg) } #endif -void -Py_FatalError(const char *msg) +static void +fatal_error(const char *prefix, const char *msg, int status) { const int fd = fileno(stderr); static int reentrant = 0; @@ -1939,7 +2035,18 @@ Py_FatalError(const char *msg) } reentrant = 1; - fprintf(stderr, "Fatal Python error: %s\n", msg); + fprintf(stderr, "Fatal Python error: "); + if (prefix) { + fputs(prefix, stderr); + fputs(": ", stderr); + } + if (msg) { + fputs(msg, stderr); + } + else { + fprintf(stderr, "<message not set>"); + } + fputs("\n", stderr); fflush(stderr); /* it helps in Windows debug build */ /* Print the exception (if an exception is set) with its traceback, @@ -1965,10 +2072,30 @@ Py_FatalError(const char *msg) #endif /* MS_WINDOWS */ exit: + if (status < 0) { #if defined(MS_WINDOWS) && defined(_DEBUG) - DebugBreak(); + DebugBreak(); #endif - abort(); + abort(); + } + else { + exit(status); + } +} + +void +Py_FatalError(const char *msg) +{ + fatal_error(NULL, msg, -1); +} + +void +_Py_FatalInitError(_PyInitError err) +{ + /* On "user" error: exit with status 1. + For all other errors, call abort(). */ + int status = err.user_err ? 1 : -1; + fatal_error(err.prefix, err.msg, status); } /* Clean up and exit */ @@ -2045,7 +2172,7 @@ Py_Exit(int sts) exit(sts); } -static void +static _PyInitError initsigs(void) { #ifdef SIGPIPE @@ -2059,8 +2186,9 @@ initsigs(void) #endif PyOS_InitInterrupts(); /* May imply initsignal() */ if (PyErr_Occurred()) { - Py_FatalError("Py_Initialize: can't import signal"); + return _Py_INIT_ERR("can't import signal"); } + return _Py_INIT_OK(); } diff --git a/Python/pystate.c b/Python/pystate.c index 55ff649..30f214e 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -35,7 +35,7 @@ to avoid the expense of doing their own locking). extern "C" { #endif -void +_PyInitError _PyRuntimeState_Init(_PyRuntimeState *runtime) { memset(runtime, 0, sizeof(*runtime)); @@ -46,17 +46,19 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) _PyEval_Initialize(&runtime->ceval); runtime->gilstate.check_enabled = 1; + /* A TSS key must be initialized with Py_tss_NEEDS_INIT in accordance with the specification. */ - { - Py_tss_t initial = Py_tss_NEEDS_INIT; - runtime->gilstate.autoTSSkey = initial; - } + Py_tss_t initial = Py_tss_NEEDS_INIT; + runtime->gilstate.autoTSSkey = initial; runtime->interpreters.mutex = PyThread_allocate_lock(); - if (runtime->interpreters.mutex == NULL) - Py_FatalError("Can't initialize threads for interpreter"); + if (runtime->interpreters.mutex == NULL) { + return _Py_INIT_ERR("Can't initialize threads for interpreter"); + } + runtime->interpreters.next_id = -1; + return _Py_INIT_OK(); } void diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 6dc8e08..d786739 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1582,13 +1582,23 @@ PySys_ResetWarnOptions(void) PyList_SetSlice(warnoptions, 0, PyList_GET_SIZE(warnoptions), NULL); } -void -PySys_AddWarnOptionUnicode(PyObject *unicode) +int +_PySys_AddWarnOptionWithError(PyObject *option) { PyObject *warnoptions = get_warnoptions(); - if (warnoptions == NULL) - return; - PyList_Append(warnoptions, unicode); + if (warnoptions == NULL) { + return -1; + } + if (PyList_Append(warnoptions, option)) { + return -1; + } + return 0; +} + +void +PySys_AddWarnOptionUnicode(PyObject *option) +{ + (void)_PySys_AddWarnOptionWithError(option); } void @@ -1627,18 +1637,17 @@ get_xoptions(void) return xoptions; } -void -PySys_AddXOption(const wchar_t *s) +int +_PySys_AddXOptionWithError(const wchar_t *s) { - PyObject *opts; PyObject *name = NULL, *value = NULL; - const wchar_t *name_end; - opts = get_xoptions(); - if (opts == NULL) + PyObject *opts = get_xoptions(); + if (opts == NULL) { goto error; + } - name_end = wcschr(s, L'='); + const wchar_t *name_end = wcschr(s, L'='); if (!name_end) { name = PyUnicode_FromWideChar(s, -1); value = Py_True; @@ -1648,19 +1657,30 @@ PySys_AddXOption(const wchar_t *s) name = PyUnicode_FromWideChar(s, name_end - s); value = PyUnicode_FromWideChar(name_end + 1, -1); } - if (name == NULL || value == NULL) + if (name == NULL || value == NULL) { + goto error; + } + if (PyDict_SetItem(opts, name, value) < 0) { goto error; - PyDict_SetItem(opts, name, value); + } Py_DECREF(name); Py_DECREF(value); - return; + return 0; error: Py_XDECREF(name); Py_XDECREF(value); - /* No return value, therefore clear error state if possible */ - if (_PyThreadState_UncheckedGet()) { - PyErr_Clear(); + return -1; +} + +void +PySys_AddXOption(const wchar_t *s) +{ + if (_PySys_AddXOptionWithError(s) < 0) { + /* No return value, therefore clear error state if possible */ + if (_PyThreadState_UncheckedGet()) { + PyErr_Clear(); + } } } @@ -1999,50 +2019,52 @@ static struct PyModuleDef sysmodule = { #define SET_SYS_FROM_STRING_BORROW(key, value) \ do { \ PyObject *v = (value); \ - if (v == NULL) \ - return NULL; \ + if (v == NULL) { \ + goto err_occurred; \ + } \ res = PyDict_SetItemString(sysdict, key, v); \ if (res < 0) { \ - return NULL; \ + goto err_occurred; \ } \ } while (0) #define SET_SYS_FROM_STRING(key, value) \ do { \ PyObject *v = (value); \ - if (v == NULL) \ - return NULL; \ + if (v == NULL) { \ + goto err_occurred; \ + } \ res = PyDict_SetItemString(sysdict, key, v); \ Py_DECREF(v); \ if (res < 0) { \ - return NULL; \ + goto err_occurred; \ } \ } while (0) -PyObject * -_PySys_BeginInit(void) + +_PyInitError +_PySys_BeginInit(PyObject **sysmod) { PyObject *m, *sysdict, *version_info; int res; m = _PyModule_CreateInitialized(&sysmodule, PYTHON_API_VERSION); - if (m == NULL) - return NULL; + if (m == NULL) { + return _Py_INIT_ERR("failed to create a module object"); + } sysdict = PyModule_GetDict(m); /* Check that stdin is not a directory - Using shell redirection, you can redirect stdin to a directory, - crashing the Python interpreter. Catch this common mistake here - and output a useful error message. Note that under MS Windows, - the shell already prevents that. */ -#if !defined(MS_WINDOWS) + Using shell redirection, you can redirect stdin to a directory, + crashing the Python interpreter. Catch this common mistake here + and output a useful error message. Note that under MS Windows, + the shell already prevents that. */ +#ifndef MS_WINDOWS { struct _Py_stat_struct sb; if (_Py_fstat_noraise(fileno(stdin), &sb) == 0 && S_ISDIR(sb.st_mode)) { - /* There's nothing more we can do. */ - /* Py_FatalError() will core dump, so just exit. */ - PySys_WriteStderr("Python error: <stdin> is a directory, cannot continue\n"); - exit(EXIT_FAILURE); + return _Py_INIT_USER_ERR("<stdin> is a directory, " + "cannot continue"); } } #endif @@ -2078,8 +2100,9 @@ _PySys_BeginInit(void) PyLong_GetInfo()); /* initialize hash_info */ if (Hash_InfoType.tp_name == NULL) { - if (PyStructSequence_InitType2(&Hash_InfoType, &hash_info_desc) < 0) - return NULL; + if (PyStructSequence_InitType2(&Hash_InfoType, &hash_info_desc) < 0) { + goto type_init_failed; + } } SET_SYS_FROM_STRING("hash_info", get_hash_info()); @@ -2109,8 +2132,9 @@ _PySys_BeginInit(void) /* version_info */ if (VersionInfoType.tp_name == NULL) { if (PyStructSequence_InitType2(&VersionInfoType, - &version_info_desc) < 0) - return NULL; + &version_info_desc) < 0) { + goto type_init_failed; + } } version_info = make_version_info(); SET_SYS_FROM_STRING("version_info", version_info); @@ -2126,8 +2150,9 @@ _PySys_BeginInit(void) /* flags */ if (FlagsType.tp_name == 0) { - if (PyStructSequence_InitType2(&FlagsType, &flags_desc) < 0) - return NULL; + if (PyStructSequence_InitType2(&FlagsType, &flags_desc) < 0) { + goto type_init_failed; + } } /* Set flags to their default values */ SET_SYS_FROM_STRING("flags", make_flags()); @@ -2136,14 +2161,17 @@ _PySys_BeginInit(void) /* getwindowsversion */ if (WindowsVersionType.tp_name == 0) if (PyStructSequence_InitType2(&WindowsVersionType, - &windows_version_desc) < 0) - return NULL; + &windows_version_desc) < 0) { + goto type_init_failed; + } /* prevent user from creating new instances */ WindowsVersionType.tp_init = NULL; WindowsVersionType.tp_new = NULL; + assert(!PyErr_Occurred()); res = PyDict_DelItemString(WindowsVersionType.tp_dict, "__new__"); - if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) + if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) { PyErr_Clear(); + } #endif /* float repr style: 0.03 (short) vs 0.029999999999999999 (legacy) */ @@ -2161,13 +2189,22 @@ _PySys_BeginInit(void) if (AsyncGenHooksType.tp_name == NULL) { if (PyStructSequence_InitType2( &AsyncGenHooksType, &asyncgen_hooks_desc) < 0) { - return NULL; + goto type_init_failed; } } - if (PyErr_Occurred()) - return NULL; - return m; + if (PyErr_Occurred()) { + goto err_occurred; + } + + *sysmod = m; + return _Py_INIT_OK(); + +type_init_failed: + return _Py_INIT_ERR("failed to initialize a type"); + +err_occurred: + return _Py_INIT_ERR("can't initialize sys module"); } #undef SET_SYS_FROM_STRING |