summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-11-15 23:48:08 (GMT)
committerGitHub <noreply@github.com>2017-11-15 23:48:08 (GMT)
commitf7e5b56c37eb859e225e886c79c5d742c567ee95 (patch)
tree7d722ca38595aaa68e02a1ee1ea53e17a54b0188 /Python
parent43605e6bfa8d49612df4a38460d063d6ba781906 (diff)
downloadcpython-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.c19
-rw-r--r--Python/frozenmain.c8
-rw-r--r--Python/import.c33
-rw-r--r--Python/pylifecycle.c394
-rw-r--r--Python/pystate.c16
-rw-r--r--Python/sysmodule.c137
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