summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-11-15 15:48:08 -0800
committerGitHub <noreply@github.com>2017-11-15 15:48:08 -0800
commitf7e5b56c37eb859e225e886c79c5d742c567ee95 (patch)
tree7d722ca38595aaa68e02a1ee1ea53e17a54b0188
parent43605e6bfa8d49612df4a38460d063d6ba781906 (diff)
downloadcpython-git-f7e5b56c37eb859e225e886c79c5d742c567ee95.tar.gz
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)
-rw-r--r--Include/import.h2
-rw-r--r--Include/internal/pystate.h8
-rw-r--r--Include/pylifecycle.h44
-rw-r--r--Include/pymem.h4
-rw-r--r--Include/sysmodule.h5
-rw-r--r--Modules/faulthandler.c79
-rw-r--r--Modules/main.c1122
-rw-r--r--Objects/obmalloc.c77
-rw-r--r--PCbuild/python.vcxproj4
-rw-r--r--Parser/pgenmain.c4
-rw-r--r--Programs/_freeze_importlib.c5
-rw-r--r--Programs/python.c14
-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
18 files changed, 1332 insertions, 643 deletions
diff --git a/Include/import.h b/Include/import.h
index c30f3ea339..26c4b1f18e 100644
--- a/Include/import.h
+++ b/Include/import.h
@@ -8,7 +8,7 @@ extern "C" {
#endif
#ifndef Py_LIMITED_API
-PyAPI_FUNC(void) _PyImportZip_Init(void);
+PyAPI_FUNC(_PyInitError) _PyImportZip_Init(void);
PyMODINIT_FUNC PyInit_imp(void);
#endif /* !Py_LIMITED_API */
diff --git a/Include/internal/pystate.h b/Include/internal/pystate.h
index 210917bb32..516f829ac3 100644
--- a/Include/internal/pystate.h
+++ b/Include/internal/pystate.h
@@ -74,10 +74,16 @@ typedef struct pyruntimestate {
// XXX Consolidate globals found via the check-c-globals script.
} _PyRuntimeState;
+#define _PyRuntimeState_INIT {.initialized = 0, .core_initialized = 0}
+
PyAPI_DATA(_PyRuntimeState) _PyRuntime;
-PyAPI_FUNC(void) _PyRuntimeState_Init(_PyRuntimeState *);
+PyAPI_FUNC(_PyInitError) _PyRuntimeState_Init(_PyRuntimeState *);
PyAPI_FUNC(void) _PyRuntimeState_Fini(_PyRuntimeState *);
+/* Initialize _PyRuntimeState.
+ Return NULL on success, or return an error message on failure. */
+PyAPI_FUNC(_PyInitError) _PyRuntime_Initialize(void);
+
#define _Py_CURRENTLY_FINALIZING(tstate) \
(_PyRuntime.finalizing == tstate)
diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h
index f7286f3764..a75b77cc73 100644
--- a/Include/pylifecycle.h
+++ b/Include/pylifecycle.h
@@ -20,18 +20,44 @@ PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void);
PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding,
const char *errors);
+typedef struct {
+ const char *prefix;
+ const char *msg;
+ int user_err;
+} _PyInitError;
+
+/* Almost all errors causing Python initialization to fail */
+#ifdef _MSC_VER
+ /* Visual Studio 2015 doesn't implement C99 __func__ in C */
+# define _Py_INIT_GET_FUNC() __FUNCTION__
+#else
+# define _Py_INIT_GET_FUNC() __func__
+#endif
+
+#define _Py_INIT_OK() \
+ (_PyInitError){.prefix = NULL, .msg = NULL, .user_err = 0}
+#define _Py_INIT_ERR(MSG) \
+ (_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 0}
+/* Error that can be fixed by the user like invalid input parameter.
+ Don't abort() the process on such error. */
+#define _Py_INIT_USER_ERR(MSG) \
+ (_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 1}
+#define _Py_INIT_FAILED(err) \
+ (err.msg != NULL)
+
/* PEP 432 Multi-phase initialization API (Private while provisional!) */
-PyAPI_FUNC(void) _Py_InitializeCore(const _PyCoreConfig *);
+PyAPI_FUNC(_PyInitError) _Py_InitializeCore(const _PyCoreConfig *);
PyAPI_FUNC(int) _Py_IsCoreInitialized(void);
-PyAPI_FUNC(int) _Py_ReadMainInterpreterConfig(_PyMainInterpreterConfig *);
-PyAPI_FUNC(int) _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *);
+PyAPI_FUNC(_PyInitError) _Py_ReadMainInterpreterConfig(_PyMainInterpreterConfig *);
+PyAPI_FUNC(_PyInitError) _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *);
#endif
/* Initialization and finalization */
PyAPI_FUNC(void) Py_Initialize(void);
PyAPI_FUNC(void) Py_InitializeEx(int);
#ifndef Py_LIMITED_API
-PyAPI_FUNC(void) _Py_InitializeEx_Private(int, int);
+PyAPI_FUNC(_PyInitError) _Py_InitializeEx_Private(int, int);
+PyAPI_FUNC(void) _Py_FatalInitError(_PyInitError err) _Py_NO_RETURN;
#endif
PyAPI_FUNC(void) Py_Finalize(void);
PyAPI_FUNC(int) Py_FinalizeEx(void);
@@ -50,7 +76,7 @@ PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(void));
#endif
PyAPI_FUNC(int) Py_AtExit(void (*func)(void));
-PyAPI_FUNC(void) Py_Exit(int);
+PyAPI_FUNC(void) Py_Exit(int) _Py_NO_RETURN;
/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. */
#ifndef Py_LIMITED_API
@@ -86,15 +112,15 @@ PyAPI_FUNC(const char *) _Py_gitversion(void);
/* Internal -- various one-time initializations */
#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _PyBuiltin_Init(void);
-PyAPI_FUNC(PyObject *) _PySys_BeginInit(void);
+PyAPI_FUNC(_PyInitError) _PySys_BeginInit(PyObject **sysmod);
PyAPI_FUNC(int) _PySys_EndInit(PyObject *sysdict);
-PyAPI_FUNC(void) _PyImport_Init(void);
+PyAPI_FUNC(_PyInitError) _PyImport_Init(void);
PyAPI_FUNC(void) _PyExc_Init(PyObject * bltinmod);
-PyAPI_FUNC(void) _PyImportHooks_Init(void);
+PyAPI_FUNC(_PyInitError) _PyImportHooks_Init(void);
PyAPI_FUNC(int) _PyFrame_Init(void);
PyAPI_FUNC(int) _PyFloat_Init(void);
PyAPI_FUNC(int) PyByteArray_Init(void);
-PyAPI_FUNC(void) _Py_HashRandomization_Init(_PyCoreConfig *core_config);
+PyAPI_FUNC(_PyInitError) _Py_HashRandomization_Init(_PyCoreConfig *core_config);
#endif
/* Various internal finalizers */
diff --git a/Include/pymem.h b/Include/pymem.h
index 2670dcdfa9..928851a3d7 100644
--- a/Include/pymem.h
+++ b/Include/pymem.h
@@ -223,6 +223,10 @@ PyAPI_FUNC(void) PyMem_SetAllocator(PyMemAllocatorDomain domain,
PyAPI_FUNC(void) PyMem_SetupDebugHooks(void);
#endif
+#ifdef Py_BUILD_CORE
+PyAPI_FUNC(void) _PyMem_GetDefaultRawAllocator(PyMemAllocatorEx *alloc);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/Include/sysmodule.h b/Include/sysmodule.h
index c5547ff674..719ecfcf61 100644
--- a/Include/sysmodule.h
+++ b/Include/sysmodule.h
@@ -37,6 +37,11 @@ PyAPI_FUNC(PyObject *) PySys_GetXOptions(void);
PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *);
#endif
+#ifdef Py_BUILD_CORE
+PyAPI_FUNC(int) _PySys_AddXOptionWithError(const wchar_t *s);
+PyAPI_FUNC(int) _PySys_AddWarnOptionWithError(PyObject *option);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
index 33edc0547e..b6d5aee9b1 100644
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -1281,47 +1281,54 @@ PyInit_faulthandler(void)
return m;
}
-/* Call faulthandler.enable() if the PYTHONFAULTHANDLER environment variable
- is defined, or if sys._xoptions has a 'faulthandler' key. */
-
static int
-faulthandler_env_options(void)
+faulthandler_init_enable(void)
{
- PyObject *xoptions, *key, *module, *res;
- char *p;
+ PyObject *module = PyImport_ImportModule("faulthandler");
+ if (module == NULL) {
+ return -1;
+ }
- if (!((p = Py_GETENV("PYTHONFAULTHANDLER")) && *p != '\0')) {
- /* PYTHONFAULTHANDLER environment variable is missing
- or an empty string */
- int has_key;
+ PyObject *res = _PyObject_CallMethodId(module, &PyId_enable, NULL);
+ Py_DECREF(module);
+ if (res == NULL) {
+ return -1;
+ }
+ Py_DECREF(res);
- xoptions = PySys_GetXOptions();
- if (xoptions == NULL)
- return -1;
+ return 0;
+}
- key = PyUnicode_FromString("faulthandler");
- if (key == NULL)
- return -1;
+/* Call faulthandler.enable() if the PYTHONFAULTHANDLER environment variable
+ is defined, or if sys._xoptions has a 'faulthandler' key. */
- has_key = PyDict_Contains(xoptions, key);
- Py_DECREF(key);
- if (has_key <= 0)
- return has_key;
+static int
+faulthandler_init_parse(void)
+{
+ char *p = Py_GETENV("PYTHONFAULTHANDLER");
+ if (p && *p != '\0') {
+ return 1;
}
- module = PyImport_ImportModule("faulthandler");
- if (module == NULL) {
+ /* PYTHONFAULTHANDLER environment variable is missing
+ or an empty string */
+ PyObject *xoptions = PySys_GetXOptions();
+ if (xoptions == NULL) {
return -1;
}
- res = _PyObject_CallMethodId(module, &PyId_enable, NULL);
- Py_DECREF(module);
- if (res == NULL)
+
+ PyObject *key = PyUnicode_FromString("faulthandler");
+ if (key == NULL) {
return -1;
- Py_DECREF(res);
- return 0;
+ }
+
+ int has_key = PyDict_Contains(xoptions, key);
+ Py_DECREF(key);
+ return has_key;
}
-int _PyFaulthandler_Init(void)
+_PyInitError
+_PyFaulthandler_Init(void)
{
#ifdef HAVE_SIGALTSTACK
int err;
@@ -1345,14 +1352,22 @@ int _PyFaulthandler_Init(void)
thread.cancel_event = PyThread_allocate_lock();
thread.running = PyThread_allocate_lock();
if (!thread.cancel_event || !thread.running) {
- PyErr_SetString(PyExc_RuntimeError,
- "could not allocate locks for faulthandler");
- return -1;
+ return _Py_INIT_ERR("failed to allocate locks for faulthandler");
}
PyThread_acquire_lock(thread.cancel_event, 1);
#endif
- return faulthandler_env_options();
+ int enable = faulthandler_init_parse();
+ if (enable < 0) {
+ return _Py_INIT_ERR("failed to parse faulthandler env var and cmdline");
+ }
+
+ if (enable) {
+ if (faulthandler_init_enable() < 0) {
+ return _Py_INIT_ERR("failed to enable faulthandler");
+ }
+ }
+ return _Py_INIT_OK();
}
void _PyFaulthandler_Fini(void)
diff --git a/Modules/main.c b/Modules/main.c
index 54abbcc547..6391ba78d8 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -2,6 +2,7 @@
#include "Python.h"
#include "osdefs.h"
+#include "internal/pystate.h"
#include <locale.h>
@@ -37,7 +38,7 @@ extern "C" {
/* For Py_GetArgcArgv(); set by main() */
static wchar_t **orig_argv;
-static int orig_argc;
+static int orig_argc;
/* command line options */
#define BASE_OPTS L"bBc:dEhiIJm:OqRsStuvVW:xX:?"
@@ -109,13 +110,13 @@ static const char usage_6[] =
" coercion behavior. Use PYTHONCOERCECLOCALE=warn to request display of\n"
" locale coercion and locale compatibility warnings on stderr.\n";
-static int
-usage(int exitcode, const wchar_t* program)
+static void
+usage(int error, const wchar_t* program)
{
- FILE *f = exitcode ? stderr : stdout;
+ FILE *f = error ? stderr : stdout;
fprintf(f, usage_line, program);
- if (exitcode)
+ if (error)
fprintf(f, "Try `python -h' for more information.\n");
else {
fputs(usage_1, f);
@@ -125,50 +126,57 @@ usage(int exitcode, const wchar_t* program)
fprintf(f, usage_5, (wint_t)DELIM, PYTHONHOMEHELP);
fputs(usage_6, f);
}
- return exitcode;
}
-static void RunStartupFile(PyCompilerFlags *cf)
+static void
+pymain_run_statup(PyCompilerFlags *cf)
{
char *startup = Py_GETENV("PYTHONSTARTUP");
- if (startup != NULL && startup[0] != '\0') {
- FILE *fp = _Py_fopen(startup, "r");
- if (fp != NULL) {
- (void) PyRun_SimpleFileExFlags(fp, startup, 0, cf);
- PyErr_Clear();
- fclose(fp);
- } else {
- int save_errno;
-
- save_errno = errno;
- PySys_WriteStderr("Could not open PYTHONSTARTUP\n");
- errno = save_errno;
- PyErr_SetFromErrnoWithFilename(PyExc_OSError,
- startup);
- PyErr_Print();
- PyErr_Clear();
- }
+ if (startup == NULL || startup[0] == '\0') {
+ return;
+ }
+
+ FILE *fp = _Py_fopen(startup, "r");
+ if (fp == NULL) {
+ int save_errno = errno;
+ PySys_WriteStderr("Could not open PYTHONSTARTUP\n");
+ errno = save_errno;
+
+ PyErr_SetFromErrnoWithFilename(PyExc_OSError,
+ startup);
+ PyErr_Print();
+ PyErr_Clear();
+ return;
}
+
+ (void) PyRun_SimpleFileExFlags(fp, startup, 0, cf);
+ PyErr_Clear();
+ fclose(fp);
}
-static void RunInteractiveHook(void)
+static void
+pymain_run_interactive_hook(void)
{
PyObject *sys, *hook, *result;
sys = PyImport_ImportModule("sys");
- if (sys == NULL)
+ if (sys == NULL) {
goto error;
+ }
+
hook = PyObject_GetAttrString(sys, "__interactivehook__");
Py_DECREF(sys);
- if (hook == NULL)
+ if (hook == NULL) {
PyErr_Clear();
- else {
- result = _PyObject_CallNoArg(hook);
- Py_DECREF(hook);
- if (result == NULL)
- goto error;
- else
- Py_DECREF(result);
+ return;
+ }
+
+ result = _PyObject_CallNoArg(hook);
+ Py_DECREF(hook);
+ if (result == NULL) {
+ goto error;
}
+ Py_DECREF(result);
+
return;
error:
@@ -178,7 +186,8 @@ error:
}
-static int RunModule(wchar_t *modname, int set_argv0)
+static int
+pymain_run_module(wchar_t *modname, int set_argv0)
{
PyObject *module, *runpy, *runmodule, *runargs, *result;
runpy = PyImport_ImportModule("runpy");
@@ -228,23 +237,26 @@ static int RunModule(wchar_t *modname, int set_argv0)
}
static PyObject *
-AsImportPathEntry(wchar_t *filename)
+pymain_get_importer(wchar_t *filename)
{
PyObject *sys_path0 = NULL, *importer;
sys_path0 = PyUnicode_FromWideChar(filename, wcslen(filename));
- if (sys_path0 == NULL)
+ if (sys_path0 == NULL) {
goto error;
+ }
importer = PyImport_GetImporter(sys_path0);
- if (importer == NULL)
+ if (importer == NULL) {
goto error;
+ }
if (importer == Py_None) {
Py_DECREF(sys_path0);
Py_DECREF(importer);
return NULL;
}
+
Py_DECREF(importer);
return sys_path0;
@@ -258,49 +270,25 @@ error:
static int
-RunMainFromImporter(PyObject *sys_path0)
-{
- PyObject *sys_path;
- int sts;
-
- /* Assume sys_path0 has already been checked by AsImportPathEntry,
- * so put it in sys.path[0] and import __main__ */
- sys_path = PySys_GetObject("path");
- if (sys_path == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path");
- goto error;
- }
- sts = PyList_Insert(sys_path, 0, sys_path0);
- if (sts) {
- sys_path0 = NULL;
- goto error;
- }
-
- sts = RunModule(L"__main__", 0);
- return sts != 0;
-
-error:
- Py_XDECREF(sys_path0);
- PyErr_Print();
- return 1;
-}
-
-static int
-run_command(wchar_t *command, PyCompilerFlags *cf)
+pymain_run_command(wchar_t *command, PyCompilerFlags *cf)
{
PyObject *unicode, *bytes;
int ret;
unicode = PyUnicode_FromWideChar(command, -1);
- if (unicode == NULL)
+ if (unicode == NULL) {
goto error;
+ }
+
bytes = PyUnicode_AsUTF8String(unicode);
Py_DECREF(unicode);
- if (bytes == NULL)
+ if (bytes == NULL) {
goto error;
+ }
+
ret = PyRun_SimpleStringFlags(PyBytes_AsString(bytes), cf);
Py_DECREF(bytes);
- return ret != 0;
+ return (ret != 0);
error:
PySys_WriteStderr("Unable to decode the command from the command line:\n");
@@ -308,8 +296,9 @@ error:
return 1;
}
+
static int
-run_file(FILE *fp, const wchar_t *filename, PyCompilerFlags *p_cf)
+pymain_run_file(FILE *fp, const wchar_t *filename, PyCompilerFlags *p_cf)
{
PyObject *unicode, *bytes = NULL;
const char *filename_str;
@@ -327,15 +316,17 @@ run_file(FILE *fp, const wchar_t *filename, PyCompilerFlags *p_cf)
bytes = PyUnicode_EncodeFSDefault(unicode);
Py_DECREF(unicode);
}
- if (bytes != NULL)
+ if (bytes != NULL) {
filename_str = PyBytes_AsString(bytes);
+ }
else {
PyErr_Clear();
filename_str = "<encoding error>";
}
}
- else
+ else {
filename_str = "<stdin>";
+ }
run = PyRun_AnyFileExFlags(fp, filename_str, filename != NULL, p_cf);
Py_XDECREF(bytes);
@@ -348,10 +339,15 @@ run_file(FILE *fp, const wchar_t *filename, PyCompilerFlags *p_cf)
/*TODO: Add arg processing to PEP 432 as a new configuration setup API
*/
typedef struct {
+ size_t len;
+ wchar_t **options;
+} _Py_OptList;
+
+typedef struct {
wchar_t *filename; /* Trailing arg without -c or -m */
wchar_t *command; /* -c argument */
wchar_t *module; /* -m argument */
- PyObject *warning_options; /* -W options */
+ _Py_OptList warning_options; /* -W options */
PyObject *extra_options; /* -X options */
int print_help; /* -h, -? options */
int print_version; /* -V option */
@@ -368,36 +364,189 @@ typedef struct {
int verbosity; /* Py_VerboseFlag */
int quiet_flag; /* Py_QuietFlag */
int skip_first_line; /* -x option */
+ _Py_OptList xoptions; /* -X options */
} _Py_CommandLineDetails;
-#define _Py_CommandLineDetails_INIT \
- {NULL, NULL, NULL, NULL, NULL, \
- 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0}
+/* Structure used by Py_Main() to pass data to subfunctions */
+typedef struct {
+ /* Exit status ("exit code") */
+ int status;
+ PyCompilerFlags cf;
+ /* non-zero is stdin is a TTY or if -i option is used */
+ int stdin_is_interactive;
+ _PyCoreConfig core_config;
+ _Py_CommandLineDetails cmdline;
+ PyObject *main_importer_path;
+ /* non-zero if filename, command (-c) or module (-m) is set
+ on the command line */
+ int run_code;
+ wchar_t *program_name;
+ /* Error message if a function failed */
+ _PyInitError err;
+ /* PYTHONWARNINGS env var */
+ _Py_OptList env_warning_options;
+ int argc;
+ wchar_t **argv;
+} _PyMain;
+
+/* .cmdline is initialized to zeros */
+#define _PyMain_INIT \
+ {.status = 0, \
+ .cf = {.cf_flags = 0}, \
+ .core_config = _PyCoreConfig_INIT, \
+ .main_importer_path = NULL, \
+ .run_code = -1, \
+ .program_name = NULL, \
+ .err = _Py_INIT_OK(), \
+ .env_warning_options = {0, NULL}}
+
+
+#define INIT_NO_MEMORY() _Py_INIT_ERR("memory allocation failed")
+
+
+static void
+pymain_optlist_clear(_Py_OptList *list)
+{
+ for (size_t i=0; i < list->len; i++) {
+ PyMem_RawFree(list->options[i]);
+ }
+ PyMem_RawFree(list->options);
+ list->len = 0;
+ list->options = NULL;
+}
+
+static void
+pymain_free_impl(_PyMain *pymain)
+{
+ _Py_CommandLineDetails *cmdline = &pymain->cmdline;
+ pymain_optlist_clear(&cmdline->warning_options);
+ pymain_optlist_clear(&cmdline->xoptions);
+ PyMem_RawFree(cmdline->command);
+
+ pymain_optlist_clear(&pymain->env_warning_options);
+ Py_CLEAR(pymain->main_importer_path);
+ PyMem_RawFree(pymain->program_name);
+
+#ifdef __INSURE__
+ /* Insure++ is a memory analysis tool that aids in discovering
+ * memory leaks and other memory problems. On Python exit, the
+ * interned string dictionaries are flagged as being in use at exit
+ * (which it is). Under normal circumstances, this is fine because
+ * the memory will be automatically reclaimed by the system. Under
+ * memory debugging, it's a huge source of useless noise, so we
+ * trade off slower shutdown for less distraction in the memory
+ * reports. -baw
+ */
+ _Py_ReleaseInternedUnicodeStrings();
+#endif /* __INSURE__ */
+}
+
+static void
+pymain_free(_PyMain *pymain)
+{
+ /* Call pymain_free() with the memory allocator used by pymain_init() */
+ PyMemAllocatorEx old_alloc, raw_alloc;
+ PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+ _PyMem_GetDefaultRawAllocator(&raw_alloc);
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &raw_alloc);
+
+ pymain_free_impl(pymain);
+
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+}
+
+
+static int
+pymain_run_main_from_importer(_PyMain *pymain)
+{
+ PyObject *sys_path0 = pymain->main_importer_path;
+ PyObject *sys_path;
+ int sts;
+
+ /* Assume sys_path0 has already been checked by pymain_get_importer(),
+ * so put it in sys.path[0] and import __main__ */
+ sys_path = PySys_GetObject("path");
+ if (sys_path == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path");
+ goto error;
+ }
+
+ sts = PyList_Insert(sys_path, 0, sys_path0);
+ if (sts) {
+ sys_path0 = NULL;
+ goto error;
+ }
+
+ sts = pymain_run_module(L"__main__", 0);
+ return sts != 0;
+
+error:
+ Py_CLEAR(pymain->main_importer_path);
+ PyErr_Print();
+ return 1;
+}
+
+
+static wchar_t*
+pymain_strdup(wchar_t *str)
+{
+ size_t len = wcslen(str) + 1; /* +1 for NUL character */
+ wchar_t *str2 = PyMem_RawMalloc(sizeof(wchar_t) * len);
+ if (str2 == NULL) {
+ return NULL;
+ }
+ memcpy(str2, str, len * sizeof(wchar_t));
+ return str2;
+}
+
+
+static int
+pymain_optlist_append(_Py_OptList *list, wchar_t *str)
+{
+ wchar_t *str2 = pymain_strdup(str);
+ if (str2 == NULL) {
+ return -1;
+ }
+
+ size_t size = (list->len + 1) * sizeof(list[0]);
+ wchar_t **options2 = (wchar_t **)PyMem_RawRealloc(list->options, size);
+ if (options2 == NULL) {
+ PyMem_RawFree(str2);
+ return -1;
+ }
+ options2[list->len] = str2;
+ list->options = options2;
+ list->len++;
+ return 0;
+}
+
+/* Parse the command line arguments
+ Return 0 on success.
+ Return 1 if parsing failed.
+ Set pymain->err and return -1 on other errors. */
static int
-read_command_line(int argc, wchar_t **argv, _Py_CommandLineDetails *cmdline)
+pymain_parse_cmdline(_PyMain *pymain)
{
- PyObject *warning_option = NULL;
- wchar_t *command = NULL;
- wchar_t *module = NULL;
- int c;
+ _Py_CommandLineDetails *cmdline = &pymain->cmdline;
_PyOS_ResetGetOpt();
+ do {
+ int c = _PyOS_GetOpt(pymain->argc, pymain->argv, PROGRAM_OPTS);
+ if (c == EOF) {
+ break;
+ }
- while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) {
if (c == 'c') {
- size_t len;
/* -c is the last option; following arguments
that look like options are left for the
command to interpret. */
-
- len = wcslen(_PyOS_optarg) + 1 + 1;
- command = (wchar_t *)PyMem_RawMalloc(sizeof(wchar_t) * len);
- if (command == NULL)
- Py_FatalError(
- "not enough memory to copy -c argument");
- wcscpy(command, _PyOS_optarg);
+ size_t len = wcslen(_PyOS_optarg) + 1 + 1;
+ wchar_t *command = PyMem_RawMalloc(sizeof(wchar_t) * len);
+ if (command == NULL) {
+ goto out_of_memory;
+ }
+ memcpy(command, _PyOS_optarg, len * sizeof(wchar_t));
command[len - 2] = '\n';
command[len - 1] = 0;
cmdline->command = command;
@@ -408,8 +557,7 @@ read_command_line(int argc, wchar_t **argv, _Py_CommandLineDetails *cmdline)
/* -m is the last option; following arguments
that look like options are left for the
module to interpret. */
- module = _PyOS_optarg;
- cmdline->module = module;
+ cmdline->module = _PyOS_optarg;
break;
}
@@ -428,6 +576,7 @@ read_command_line(int argc, wchar_t **argv, _Py_CommandLineDetails *cmdline)
break;
case 'I':
+ pymain->core_config.ignore_environment++;
cmdline->isolated++;
cmdline->no_user_site_directory++;
break;
@@ -451,7 +600,7 @@ read_command_line(int argc, wchar_t **argv, _Py_CommandLineDetails *cmdline)
break;
case 'E':
- /* Handled prior to core initialization */
+ pymain->core_config.ignore_environment++;
break;
case 't':
@@ -480,21 +629,17 @@ read_command_line(int argc, wchar_t **argv, _Py_CommandLineDetails *cmdline)
break;
case 'W':
- if (cmdline->warning_options == NULL)
- cmdline->warning_options = PyList_New(0);
- if (cmdline->warning_options == NULL)
- Py_FatalError("failure in handling of -W argument");
- warning_option = PyUnicode_FromWideChar(_PyOS_optarg, -1);
- if (warning_option == NULL)
- Py_FatalError("failure in handling of -W argument");
- if (PyList_Append(cmdline->warning_options, warning_option) == -1)
- Py_FatalError("failure in handling of -W argument");
- Py_DECREF(warning_option);
+ if (pymain_optlist_append(&cmdline->warning_options,
+ _PyOS_optarg) < 0) {
+ goto out_of_memory;
+ }
break;
case 'X':
- /* TODO: Delay addition of X options to sys module */
- PySys_AddXOption(_PyOS_optarg);
+ if (pymain_optlist_append(&cmdline->xoptions,
+ _PyOS_optarg) < 0) {
+ goto out_of_memory;
+ }
break;
case 'q':
@@ -508,20 +653,26 @@ read_command_line(int argc, wchar_t **argv, _Py_CommandLineDetails *cmdline)
/* This space reserved for other options */
default:
- return -1;
- /*NOTREACHED*/
-
+ /* unknown argument: parsing failed */
+ return 1;
}
- }
+ } while (1);
- if (command == NULL && module == NULL && _PyOS_optind < argc &&
- wcscmp(argv[_PyOS_optind], L"-") != 0)
+ if (cmdline->command == NULL && cmdline->module == NULL
+ && _PyOS_optind < pymain->argc
+ && wcscmp(pymain->argv[_PyOS_optind], L"-") != 0)
{
- cmdline->filename = argv[_PyOS_optind];
+ cmdline->filename = pymain->argv[_PyOS_optind];
}
+
return 0;
+
+out_of_memory:
+ pymain->err = INIT_NO_MEMORY();
+ return -1;
}
+
static void
maybe_set_flag(int *flag, int value)
{
@@ -534,146 +685,142 @@ maybe_set_flag(int *flag, int value)
}
}
+
static int
-apply_command_line_and_environment(_Py_CommandLineDetails *cmdline)
+pymain_add_xoptions(_PyMain *pymain)
{
- maybe_set_flag(&Py_BytesWarningFlag, cmdline->bytes_warning);
- maybe_set_flag(&Py_DebugFlag, cmdline->debug);
- maybe_set_flag(&Py_InspectFlag, cmdline->inspect);
- maybe_set_flag(&Py_InteractiveFlag, cmdline->interactive);
- maybe_set_flag(&Py_IsolatedFlag, cmdline->isolated);
- maybe_set_flag(&Py_OptimizeFlag, cmdline->optimization_level);
- maybe_set_flag(&Py_DontWriteBytecodeFlag, cmdline->dont_write_bytecode);
- maybe_set_flag(&Py_NoUserSiteDirectory, cmdline->no_user_site_directory);
- maybe_set_flag(&Py_NoSiteFlag, cmdline->no_site_import);
- maybe_set_flag(&Py_UnbufferedStdioFlag, cmdline->use_unbuffered_io);
- maybe_set_flag(&Py_VerboseFlag, cmdline->verbosity);
- maybe_set_flag(&Py_QuietFlag, cmdline->quiet_flag);
-
- /* TODO: Apply PYTHONWARNINGS & -W options to sys module here */
- /* TODO: Apply -X options to sys module here */
+ _Py_OptList *options = &pymain->cmdline.xoptions;
+ for (size_t i=0; i < options->len; i++) {
+ wchar_t *option = options->options[i];
+ if (_PySys_AddXOptionWithError(option) < 0) {
+ pymain->err = INIT_NO_MEMORY();
+ return -1;
+ }
+ }
return 0;
}
-int
-Py_Main(int argc, wchar_t **argv)
-{
- int c;
- int sts;
- FILE *fp = stdin;
- char *p;
-#ifdef MS_WINDOWS
- wchar_t *wp;
-#endif
- int stdin_is_interactive = 0;
- _Py_CommandLineDetails cmdline = _Py_CommandLineDetails_INIT;
- _PyCoreConfig core_config = _PyCoreConfig_INIT;
- PyCompilerFlags cf;
- PyObject *main_importer_path = NULL;
-
- cf.cf_flags = 0;
- orig_argc = argc; /* For Py_GetArgcArgv() */
- orig_argv = argv;
-
- /* Hash randomization needed early for all string operations
- (including -W and -X options). */
- _PyOS_opterr = 0; /* prevent printing the error in 1st pass */
- while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) {
- if (c == 'm' || c == 'c') {
- /* -c / -m is the last option: following arguments are
- not interpreter options. */
- break;
+static int
+pymain_add_warnings_optlist(_Py_OptList *warnings)
+{
+ for (size_t i = 0; i < warnings->len; i++) {
+ PyObject *option = PyUnicode_FromWideChar(warnings->options[i], -1);
+ if (option == NULL) {
+ return -1;
}
- if (c == 'E' || c == 'I') {
- core_config.ignore_environment++;
- break;
+ if (_PySys_AddWarnOptionWithError(option)) {
+ Py_DECREF(option);
+ return -1;
}
+ Py_DECREF(option);
}
+ return 0;
+}
- /* Initialize the core language runtime */
- Py_IgnoreEnvironmentFlag = core_config.ignore_environment;
- core_config._disable_importlib = 0;
- core_config.allocator = Py_GETENV("PYTHONMALLOC");
- _Py_InitializeCore(&core_config);
+static int
+pymain_add_warnings_options(_PyMain *pymain)
+{
+ PySys_ResetWarnOptions();
- /* Reprocess the command line with the language runtime available */
- if (read_command_line(argc, argv, &cmdline)) {
- return usage(2, argv[0]);
+ if (pymain_add_warnings_optlist(&pymain->env_warning_options) < 0) {
+ pymain->err = INIT_NO_MEMORY();
+ return -1;
}
-
- if (cmdline.print_help) {
- return usage(0, argv[0]);
+ if (pymain_add_warnings_optlist(&pymain->cmdline.warning_options) < 0) {
+ pymain->err = INIT_NO_MEMORY();
+ return -1;
}
+ return 0;
+}
- if (cmdline.print_version) {
- printf("Python %s\n", cmdline.print_version >= 2 ? Py_GetVersion() : PY_VERSION);
+
+/* Get warning options from PYTHONWARNINGS environment variable.
+ Return 0 on success.
+ Set pymain->err and return -1 on error. */
+static int
+pymain_warnings_envvar(_PyMain *pymain)
+{
+ if (Py_IgnoreEnvironmentFlag) {
return 0;
}
- PySys_ResetWarnOptions();
- apply_command_line_and_environment(&cmdline);
-
#ifdef MS_WINDOWS
- if (!Py_IgnoreEnvironmentFlag && (wp = _wgetenv(L"PYTHONWARNINGS")) &&
- *wp != L'\0') {
+ wchar_t *wp;
+
+ if ((wp = _wgetenv(L"PYTHONWARNINGS")) && *wp != L'\0') {
wchar_t *buf, *warning, *context = NULL;
buf = (wchar_t *)PyMem_RawMalloc((wcslen(wp) + 1) * sizeof(wchar_t));
- if (buf == NULL)
- Py_FatalError(
- "not enough memory to copy PYTHONWARNINGS");
+ if (buf == NULL) {
+ goto out_of_memory;
+ }
wcscpy(buf, wp);
for (warning = wcstok_s(buf, L",", &context);
warning != NULL;
warning = wcstok_s(NULL, L",", &context)) {
- PySys_AddWarnOption(warning);
+
+ if (pymain_optlist_append(&pymain->env_warning_options,
+ warning) < 0) {
+ PyMem_RawFree(buf);
+ goto out_of_memory;
+ }
}
PyMem_RawFree(buf);
}
#else
+ char *p;
+
if ((p = Py_GETENV("PYTHONWARNINGS")) && *p != '\0') {
char *buf, *oldloc;
- PyObject *unicode;
/* settle for strtok here as there's no one standard
C89 wcstok */
buf = (char *)PyMem_RawMalloc(strlen(p) + 1);
- if (buf == NULL)
- Py_FatalError(
- "not enough memory to copy PYTHONWARNINGS");
+ if (buf == NULL) {
+ goto out_of_memory;
+ }
strcpy(buf, p);
oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL));
setlocale(LC_ALL, "");
for (p = strtok(buf, ","); p != NULL; p = strtok(NULL, ",")) {
-#ifdef __APPLE__
- /* Use utf-8 on Mac OS X */
- unicode = PyUnicode_FromString(p);
-#else
- unicode = PyUnicode_DecodeLocale(p, "surrogateescape");
-#endif
- if (unicode == NULL) {
- /* ignore errors */
- PyErr_Clear();
- continue;
+ size_t len;
+ wchar_t *warning = Py_DecodeLocale(p, &len);
+ if (warning == NULL) {
+ if (len == (size_t)-2) {
+ pymain->err = _Py_INIT_ERR("failed to decode "
+ "PYTHONWARNINGS");
+ return -1;
+ }
+ else {
+ goto out_of_memory;
+ }
}
- PySys_AddWarnOptionUnicode(unicode);
- Py_DECREF(unicode);
+ if (pymain_optlist_append(&pymain->env_warning_options,
+ warning) < 0) {
+ PyMem_RawFree(warning);
+ goto out_of_memory;
+ }
+ PyMem_RawFree(warning);
}
setlocale(LC_ALL, oldloc);
PyMem_RawFree(oldloc);
PyMem_RawFree(buf);
}
#endif
- if (cmdline.warning_options != NULL) {
- Py_ssize_t i;
- for (i = 0; i < PyList_GET_SIZE(cmdline.warning_options); i++) {
- PySys_AddWarnOptionUnicode(PyList_GET_ITEM(cmdline.warning_options, i));
- }
- Py_DECREF(cmdline.warning_options);
- }
+ return 0;
- stdin_is_interactive = Py_FdIsInteractive(stdin, (char *)0);
+out_of_memory:
+ pymain->err = INIT_NO_MEMORY();
+ return -1;
+}
+
+
+static void
+pymain_init_stdio(_PyMain *pymain)
+{
+ pymain->stdin_is_interactive = (isatty(fileno(stdin))
+ || Py_InteractiveFlag);
#if defined(MS_WINDOWS) || defined(__CYGWIN__)
/* don't translate newlines (\r\n <=> \n) */
@@ -706,8 +853,20 @@ Py_Main(int argc, wchar_t **argv)
#endif /* !MS_WINDOWS */
/* Leave stderr alone - it should be unbuffered anyway. */
}
+}
+
+
+/* Get the program name: use PYTHONEXECUTABLE and __PYVENV_LAUNCHER__
+ environment variables on macOS if available, use argv[0] by default.
+ Return 0 on success.
+ Set pymain->err and return -1 on error. */
+static int
+pymain_get_program_name(_PyMain *pymain)
+{
+ assert(pymain->program_name == NULL);
#ifdef __APPLE__
+ char *p;
/* On MacOS X, when the Python interpreter is embedded in an
application bundle, it gets executed by a bootstrapping script
that does os.execve() with an argv[0] that's different from the
@@ -723,171 +882,295 @@ Py_Main(int argc, wchar_t **argv)
buffer = PyMem_RawMalloc(len * sizeof(wchar_t));
if (buffer == NULL) {
- Py_FatalError(
- "not enough memory to copy PYTHONEXECUTABLE");
+ goto out_of_memory;
}
mbstowcs(buffer, p, len);
- Py_SetProgramName(buffer);
- /* buffer is now handed off - do not free */
- } else {
+ pymain->program_name = buffer;
+ }
#ifdef WITH_NEXT_FRAMEWORK
+ else {
char* pyvenv_launcher = getenv("__PYVENV_LAUNCHER__");
-
if (pyvenv_launcher && *pyvenv_launcher) {
/* Used by Mac/Tools/pythonw.c to forward
* the argv0 of the stub executable
*/
- wchar_t* wbuf = Py_DecodeLocale(pyvenv_launcher, NULL);
-
+ size_t len;
+ wchar_t* wbuf = Py_DecodeLocale(pyvenv_launcher, &len);
if (wbuf == NULL) {
- Py_FatalError("Cannot decode __PYVENV_LAUNCHER__");
+ if (len == (size_t)-2) {
+ pymain->err = _Py_INIT_ERR("failed to decode "
+ "__PYVENV_LAUNCHER__");
+ return -1;
+ }
+ else {
+ goto out_of_memory;
+ }
}
- Py_SetProgramName(wbuf);
-
- /* Don't free wbuf, the argument to Py_SetProgramName
- * must remain valid until Py_FinalizeEx is called.
- */
- } else {
- Py_SetProgramName(argv[0]);
+ pymain->program_name = wbuf;
}
-#else
- Py_SetProgramName(argv[0]);
-#endif
}
-#else
- Py_SetProgramName(argv[0]);
-#endif
- /* Replaces previous call to Py_Initialize()
- *
- * TODO: Move environment queries (etc) into Py_ReadConfig
- */
- {
- _PyMainInterpreterConfig config = _PyMainInterpreterConfig_INIT;
+#endif /* WITH_NEXT_FRAMEWORK */
+#endif /* __APPLE__ */
+
+ if (pymain->program_name == NULL) {
+ /* Use argv[0] by default */
+ pymain->program_name = pymain_strdup(pymain->argv[0]);
+ if (pymain->program_name == NULL) {
+ goto out_of_memory;
+ }
+ }
+ return 0;
+
+out_of_memory:
+ pymain->err = INIT_NO_MEMORY();
+ return -1;
+}
- /* TODO: Moar config options! */
- config.install_signal_handlers = 1;
- /* TODO: Print any exceptions raised by these operations */
- if (_Py_ReadMainInterpreterConfig(&config))
- Py_FatalError("Py_Main: Py_ReadMainInterpreterConfig failed");
- if (_Py_InitializeMainInterpreter(&config))
- Py_FatalError("Py_Main: Py_InitializeMainInterpreter failed");
+
+/* Initialize the main interpreter.
+ *
+ * Replaces previous call to Py_Initialize()
+ *
+ * TODO: Move environment queries (etc) into Py_ReadConfig
+ *
+ * Return 0 on success.
+ * Set pymain->err and return -1 on error.
+ */
+static int
+pymain_init_main_interpreter(_PyMain *pymain)
+{
+ _PyMainInterpreterConfig config = _PyMainInterpreterConfig_INIT;
+ _PyInitError err;
+
+ /* TODO: Moar config options! */
+ config.install_signal_handlers = 1;
+
+ /* TODO: Print any exceptions raised by these operations */
+ err = _Py_ReadMainInterpreterConfig(&config);
+ if (_Py_INIT_FAILED(err)) {
+ pymain->err = err;
+ return -1;
}
+ err = _Py_InitializeMainInterpreter(&config);
+ if (_Py_INIT_FAILED(err)) {
+ pymain->err = err;
+ return -1;
+ }
+ return 0;
+}
+
+
+static void
+pymain_header(_PyMain *pymain)
+{
/* TODO: Move this to _PyRun_PrepareMain */
- if (!Py_QuietFlag && (Py_VerboseFlag ||
- (cmdline.command == NULL && cmdline.filename == NULL &&
- cmdline.module == NULL && stdin_is_interactive))) {
- fprintf(stderr, "Python %s on %s\n",
- Py_GetVersion(), Py_GetPlatform());
- if (!Py_NoSiteFlag)
- fprintf(stderr, "%s\n", COPYRIGHT);
+ if (Py_QuietFlag) {
+ return;
+ }
+
+ if (!Py_VerboseFlag && (pymain->run_code || !pymain->stdin_is_interactive)) {
+ return;
}
+ fprintf(stderr, "Python %s on %s\n", Py_GetVersion(), Py_GetPlatform());
+ if (!Py_NoSiteFlag) {
+ fprintf(stderr, "%s\n", COPYRIGHT);
+ }
+}
+
+
+static void
+pymain_init_argv(_PyMain *pymain)
+{
+ _Py_CommandLineDetails *cmdline = &pymain->cmdline;
+
/* TODO: Move this to _Py_InitializeMainInterpreter */
- if (cmdline.command != NULL) {
+ if (cmdline->command != NULL) {
/* Backup _PyOS_optind and force sys.argv[0] = '-c' */
_PyOS_optind--;
- argv[_PyOS_optind] = L"-c";
+ pymain->argv[_PyOS_optind] = L"-c";
}
- if (cmdline.module != NULL) {
+ if (cmdline->module != NULL) {
/* Backup _PyOS_optind and force sys.argv[0] = '-m'*/
_PyOS_optind--;
- argv[_PyOS_optind] = L"-m";
+ pymain->argv[_PyOS_optind] = L"-m";
}
- if (cmdline.filename != NULL) {
- main_importer_path = AsImportPathEntry(cmdline.filename);
+ if (cmdline->filename != NULL) {
+ pymain->main_importer_path = pymain_get_importer(cmdline->filename);
}
- if (main_importer_path != NULL) {
- /* Let RunMainFromImporter adjust sys.path[0] later */
- PySys_SetArgvEx(argc-_PyOS_optind, argv+_PyOS_optind, 0);
+ int update_path;
+ if (pymain->main_importer_path != NULL) {
+ /* Let pymain_run_main_from_importer() adjust sys.path[0] later */
+ update_path = 0;
} else {
/* Use config settings to decide whether or not to update sys.path[0] */
- PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);
+ update_path = (Py_IsolatedFlag == 0);
}
+ PySys_SetArgvEx(pymain->argc - _PyOS_optind,
+ pymain->argv + _PyOS_optind,
+ update_path);
+}
- if ((Py_InspectFlag || (cmdline.command == NULL &&
- cmdline.filename == NULL &&
- cmdline.module == NULL)) &&
- isatty(fileno(stdin)) &&
- !Py_IsolatedFlag) {
- PyObject *v;
- v = PyImport_ImportModule("readline");
- if (v == NULL)
- PyErr_Clear();
- else
- Py_DECREF(v);
+
+/* Set Py_XXX global configuration variables */
+static void
+pymain_set_global_config(_PyMain *pymain)
+{
+ _Py_CommandLineDetails *cmdline = &pymain->cmdline;
+ maybe_set_flag(&Py_BytesWarningFlag, cmdline->bytes_warning);
+ maybe_set_flag(&Py_DebugFlag, cmdline->debug);
+ maybe_set_flag(&Py_InspectFlag, cmdline->inspect);
+ maybe_set_flag(&Py_InteractiveFlag, cmdline->interactive);
+ maybe_set_flag(&Py_IsolatedFlag, cmdline->isolated);
+ maybe_set_flag(&Py_OptimizeFlag, cmdline->optimization_level);
+ maybe_set_flag(&Py_DontWriteBytecodeFlag, cmdline->dont_write_bytecode);
+ maybe_set_flag(&Py_NoUserSiteDirectory, cmdline->no_user_site_directory);
+ maybe_set_flag(&Py_NoSiteFlag, cmdline->no_site_import);
+ maybe_set_flag(&Py_UnbufferedStdioFlag, cmdline->use_unbuffered_io);
+ maybe_set_flag(&Py_VerboseFlag, cmdline->verbosity);
+ maybe_set_flag(&Py_QuietFlag, cmdline->quiet_flag);
+
+ maybe_set_flag(&Py_IgnoreEnvironmentFlag, pymain->core_config.ignore_environment);
+}
+
+
+/* Propagate options parsed from the command line and environment variables
+ to the Python runtime.
+
+ Return 0 on success, or set pymain->err and return -1 on error. */
+static int
+pymain_configure_pyruntime(_PyMain *pymain)
+{
+ Py_SetProgramName(pymain->program_name);
+ /* Don't free program_name here: the argument to Py_SetProgramName
+ must remain valid until Py_FinalizeEx is called. The string is freed
+ by pymain_free(). */
+
+ if (pymain_add_xoptions(pymain)) {
+ return -1;
+ }
+ if (pymain_add_warnings_options(pymain)) {
+ return -1;
+ }
+ return 0;
+}
+
+
+static void
+pymain_import_readline(_PyMain *pymain)
+{
+ if (Py_IsolatedFlag) {
+ return;
+ }
+ if (!Py_InspectFlag && pymain->run_code) {
+ return;
+ }
+ if (!isatty(fileno(stdin))) {
+ return;
}
- if (cmdline.command) {
- sts = run_command(cmdline.command, &cf);
- PyMem_RawFree(cmdline.command);
- } else if (cmdline.module) {
- sts = (RunModule(cmdline.module, 1) != 0);
+ PyObject *mod = PyImport_ImportModule("readline");
+ if (mod == NULL) {
+ PyErr_Clear();
}
else {
+ Py_DECREF(mod);
+ }
+}
- if (cmdline.filename == NULL && stdin_is_interactive) {
- Py_InspectFlag = 0; /* do exit on SystemExit */
- RunStartupFile(&cf);
- RunInteractiveHook();
- }
- /* XXX */
-
- sts = -1; /* keep track of whether we've already run __main__ */
- if (main_importer_path != NULL) {
- sts = RunMainFromImporter(main_importer_path);
- }
+static FILE*
+pymain_open_filename(_PyMain *pymain)
+{
+ _Py_CommandLineDetails *cmdline = &pymain->cmdline;
+ FILE* fp;
+
+ fp = _Py_wfopen(cmdline->filename, L"r");
+ if (fp == NULL) {
+ char *cfilename_buffer;
+ const char *cfilename;
+ int err = errno;
+ cfilename_buffer = Py_EncodeLocale(cmdline->filename, NULL);
+ if (cfilename_buffer != NULL)
+ cfilename = cfilename_buffer;
+ else
+ cfilename = "<unprintable file name>";
+ fprintf(stderr, "%ls: can't open file '%s': [Errno %d] %s\n",
+ pymain->argv[0], cfilename, err, strerror(err));
+ PyMem_Free(cfilename_buffer);
+ pymain->status = 2;
+ return NULL;
+ }
- if (sts==-1 && cmdline.filename != NULL) {
- fp = _Py_wfopen(cmdline.filename, L"r");
- if (fp == NULL) {
- char *cfilename_buffer;
- const char *cfilename;
- int err = errno;
- cfilename_buffer = Py_EncodeLocale(cmdline.filename, NULL);
- if (cfilename_buffer != NULL)
- cfilename = cfilename_buffer;
- else
- cfilename = "<unprintable file name>";
- fprintf(stderr, "%ls: can't open file '%s': [Errno %d] %s\n",
- argv[0], cfilename, err, strerror(err));
- if (cfilename_buffer)
- PyMem_Free(cfilename_buffer);
- return 2;
- }
- else if (cmdline.skip_first_line) {
- int ch;
- /* Push back first newline so line numbers
- remain the same */
- while ((ch = getc(fp)) != EOF) {
- if (ch == '\n') {
- (void)ungetc(ch, fp);
- break;
- }
- }
- }
- {
- struct _Py_stat_struct sb;
- if (_Py_fstat_noraise(fileno(fp), &sb) == 0 &&
- S_ISDIR(sb.st_mode)) {
- fprintf(stderr,
- "%ls: '%ls' is a directory, cannot continue\n",
- argv[0], cmdline.filename);
- fclose(fp);
- return 1;
- }
+ if (cmdline->skip_first_line) {
+ int ch;
+ /* Push back first newline so line numbers
+ remain the same */
+ while ((ch = getc(fp)) != EOF) {
+ if (ch == '\n') {
+ (void)ungetc(ch, fp);
+ break;
}
}
+ }
+
+ struct _Py_stat_struct sb;
+ if (_Py_fstat_noraise(fileno(fp), &sb) == 0 &&
+ S_ISDIR(sb.st_mode)) {
+ fprintf(stderr,
+ "%ls: '%ls' is a directory, cannot continue\n",
+ pymain->argv[0], cmdline->filename);
+ fclose(fp);
+ pymain->status = 1;
+ return NULL;
+ }
+
+ return fp;
+}
- if (sts == -1)
- sts = run_file(fp, cmdline.filename, &cf);
+
+static void
+pymain_run(_PyMain *pymain)
+{
+ _Py_CommandLineDetails *cmdline = &pymain->cmdline;
+
+ if (cmdline->filename == NULL && pymain->stdin_is_interactive) {
+ Py_InspectFlag = 0; /* do exit on SystemExit */
+ pymain_run_statup(&pymain->cf);
+ pymain_run_interactive_hook();
+ }
+ /* XXX */
+
+ if (pymain->main_importer_path != NULL) {
+ pymain->status = pymain_run_main_from_importer(pymain);
+ return;
+ }
+
+ FILE *fp;
+ if (cmdline->filename != NULL) {
+ fp = pymain_open_filename(pymain);
+ if (fp == NULL) {
+ return;
+ }
+ }
+ else {
+ fp = stdin;
}
+ pymain->status = pymain_run_file(fp, cmdline->filename, &pymain->cf);
+}
+
+
+static void
+pymain_repl(_PyMain *pymain)
+{
+ char *p;
+
/* Check this environment variable at the end, to give programs the
* opportunity to set it from Python.
*/
@@ -897,34 +1180,185 @@ Py_Main(int argc, wchar_t **argv)
Py_InspectFlag = 1;
}
- if (Py_InspectFlag && stdin_is_interactive &&
- (cmdline.filename != NULL || cmdline.command != NULL || cmdline.module != NULL)) {
+ if (Py_InspectFlag && pymain->stdin_is_interactive && pymain->run_code) {
Py_InspectFlag = 0;
- RunInteractiveHook();
+ pymain_run_interactive_hook();
/* XXX */
- sts = PyRun_AnyFileFlags(stdin, "<stdin>", &cf) != 0;
+ int res = PyRun_AnyFileFlags(stdin, "<stdin>", &pymain->cf);
+ pymain->status = (res != 0);
+ }
+}
+
+
+/* Parse the command line.
+ Handle --version and --help options directly.
+
+ Return 1 if Python must exit.
+ Return 0 on success.
+ Set pymain->err and return -1 on failure. */
+static int
+pymain_init_cmdline(_PyMain *pymain)
+{
+ _Py_CommandLineDetails *cmdline = &pymain->cmdline;
+
+ int res = pymain_parse_cmdline(pymain);
+ if (res < 0) {
+ return -1;
+ }
+ if (res) {
+ usage(1, pymain->argv[0]);
+ pymain->status = 2;
+ return 1;
+ }
+
+ if (cmdline->print_help) {
+ usage(0, pymain->argv[0]);
+ pymain->status = 0;
+ return 1;
+ }
+
+ if (cmdline->print_version) {
+ printf("Python %s\n",
+ (cmdline->print_version >= 2) ? Py_GetVersion() : PY_VERSION);
+ return 1;
+ }
+
+ pymain->run_code = (cmdline->command != NULL || cmdline->filename != NULL
+ || cmdline->module != NULL);
+
+ return 0;
+}
+
+
+/* Initialize Py_Main().
+ This code must not use Python runtime apart PyMem_Raw memory allocator.
+
+ Return 0 on success.
+ Return 1 if Python is done and must exit.
+ Set pymain->err and return -1 on error. */
+static int
+pymain_init_impl(_PyMain *pymain)
+{
+ _PyCoreConfig *core_config = &pymain->core_config;
+ core_config->_disable_importlib = 0;
+
+ orig_argc = pymain->argc; /* For Py_GetArgcArgv() */
+ orig_argv = pymain->argv;
+
+ /* Parse the command line */
+ int res = pymain_init_cmdline(pymain);
+ if (res < 0) {
+ return -1;
+ }
+ if (res > 0) {
+ return 1;
+ }
+
+ pymain_set_global_config(pymain);
+ pymain_init_stdio(pymain);
+
+ /* Get environment variables */
+ if (pymain_warnings_envvar(pymain) < 0) {
+ return -1;
+ }
+ if (pymain_get_program_name(pymain) < 0) {
+ return -1;
}
+ core_config->allocator = Py_GETENV("PYTHONMALLOC");
+
+ return 0;
+}
+
+
+static int
+pymain_init(_PyMain *pymain)
+{
+ pymain->err = _PyRuntime_Initialize();
+ if (_Py_INIT_FAILED(pymain->err)) {
+ return -1;
+ }
+
+ /* Make sure that all memory allocated in pymain_init() is allocated
+ by malloc() */
+ PyMemAllocatorEx old_alloc, raw_alloc;
+ PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+ _PyMem_GetDefaultRawAllocator(&raw_alloc);
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &raw_alloc);
+
+ int res = pymain_init_impl(pymain);
+
+ /* Restore the old memory allocator */
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+
+ return res;
+}
+
+static int
+pymain_core(_PyMain *pymain)
+{
+ _Py_CommandLineDetails *cmdline = &pymain->cmdline;
+
+ pymain->err = _Py_InitializeCore(&pymain->core_config);
+ if (_Py_INIT_FAILED(pymain->err)) {
+ return -1;
+ }
+
+ if (pymain_configure_pyruntime(pymain)) {
+ return -1;
+ }
+
+ if (pymain_init_main_interpreter(pymain)) {
+ return -1;
+ }
+
+ pymain_header(pymain);
+ pymain_import_readline(pymain);
+
+ pymain_init_argv(pymain);
+
+ if (cmdline->command) {
+ pymain->status = pymain_run_command(cmdline->command, &pymain->cf);
+ }
+ else if (cmdline->module) {
+ pymain->status = (pymain_run_module(cmdline->module, 1) != 0);
+ }
+ else {
+ pymain_run(pymain);
+ }
+ pymain_repl(pymain);
if (Py_FinalizeEx() < 0) {
/* Value unlikely to be confused with a non-error exit status or
other special meaning */
- sts = 120;
+ pymain->status = 120;
}
-#ifdef __INSURE__
- /* Insure++ is a memory analysis tool that aids in discovering
- * memory leaks and other memory problems. On Python exit, the
- * interned string dictionaries are flagged as being in use at exit
- * (which it is). Under normal circumstances, this is fine because
- * the memory will be automatically reclaimed by the system. Under
- * memory debugging, it's a huge source of useless noise, so we
- * trade off slower shutdown for less distraction in the memory
- * reports. -baw
- */
- _Py_ReleaseInternedUnicodeStrings();
-#endif /* __INSURE__ */
+ return 0;
+}
+
+
+int
+Py_Main(int argc, wchar_t **argv)
+{
+ _PyMain pymain = _PyMain_INIT;
+ memset(&pymain.cmdline, 0, sizeof(pymain.cmdline));
+ pymain.argc = argc;
+ pymain.argv = argv;
+
+ int res = pymain_init(&pymain);
+ if (res < 0) {
+ _Py_FatalInitError(pymain.err);
+ }
+ if (res == 0) {
+ res = pymain_core(&pymain);
+ if (res < 0) {
+ _Py_FatalInitError(pymain.err);
+ }
+ }
+
+ pymain_free(&pymain);
- return sts;
+ return pymain.status;
}
/* this is gonna seem *real weird*, but if you put some other code between
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
index 4441c82ad8..699cce94d2 100644
--- a/Objects/obmalloc.c
+++ b/Objects/obmalloc.c
@@ -182,31 +182,17 @@ static struct {
#define _PyMem_Raw _PyRuntime.mem.allocators.raw
-static const PyMemAllocatorEx _pymem_raw = {
-#ifdef Py_DEBUG
- &_PyMem_Debug.raw, PYRAWDBG_FUNCS
-#else
- NULL, PYRAW_FUNCS
-#endif
- };
#define _PyMem _PyRuntime.mem.allocators.mem
-static const PyMemAllocatorEx _pymem = {
-#ifdef Py_DEBUG
- &_PyMem_Debug.mem, PYDBG_FUNCS
-#else
- NULL, PYMEM_FUNCS
-#endif
- };
#define _PyObject _PyRuntime.mem.allocators.obj
-static const PyMemAllocatorEx _pyobject = {
-#ifdef Py_DEBUG
- &_PyMem_Debug.obj, PYDBG_FUNCS
-#else
- NULL, PYOBJ_FUNCS
-#endif
- };
+
+void
+_PyMem_GetDefaultRawAllocator(PyMemAllocatorEx *alloc_p)
+{
+ PyMemAllocatorEx alloc = {NULL, PYRAW_FUNCS};
+ *alloc_p = alloc;
+}
int
_PyMem_SetupAllocators(const char *opt)
@@ -267,34 +253,52 @@ _PyMem_SetupAllocators(const char *opt)
return 0;
}
-#undef PYRAW_FUNCS
-#undef PYMEM_FUNCS
-#undef PYOBJ_FUNCS
-#undef PYRAWDBG_FUNCS
-#undef PYDBG_FUNCS
-static const PyObjectArenaAllocator _PyObject_Arena = {NULL,
+void
+_PyObject_Initialize(struct _pyobj_runtime_state *state)
+{
+ PyObjectArenaAllocator _PyObject_Arena = {NULL,
#ifdef MS_WINDOWS
- _PyObject_ArenaVirtualAlloc, _PyObject_ArenaVirtualFree
+ _PyObject_ArenaVirtualAlloc, _PyObject_ArenaVirtualFree
#elif defined(ARENAS_USE_MMAP)
- _PyObject_ArenaMmap, _PyObject_ArenaMunmap
+ _PyObject_ArenaMmap, _PyObject_ArenaMunmap
#else
- _PyObject_ArenaMalloc, _PyObject_ArenaFree
+ _PyObject_ArenaMalloc, _PyObject_ArenaFree
#endif
};
-void
-_PyObject_Initialize(struct _pyobj_runtime_state *state)
-{
state->allocator_arenas = _PyObject_Arena;
}
+
void
_PyMem_Initialize(struct _pymem_runtime_state *state)
{
- state->allocators.raw = _pymem_raw;
- state->allocators.mem = _pymem;
- state->allocators.obj = _pyobject;
+ PyMemAllocatorEx pymem_raw = {
+#ifdef Py_DEBUG
+ &_PyMem_Debug.raw, PYRAWDBG_FUNCS
+#else
+ NULL, PYRAW_FUNCS
+#endif
+ };
+ PyMemAllocatorEx pymem = {
+#ifdef Py_DEBUG
+ &_PyMem_Debug.mem, PYDBG_FUNCS
+#else
+ NULL, PYMEM_FUNCS
+#endif
+ };
+ PyMemAllocatorEx pyobject = {
+#ifdef Py_DEBUG
+ &_PyMem_Debug.obj, PYDBG_FUNCS
+#else
+ NULL, PYOBJ_FUNCS
+#endif
+ };
+
+ state->allocators.raw = pymem_raw;
+ state->allocators.mem = pymem;
+ state->allocators.obj = pyobject;
#ifdef WITH_PYMALLOC
Py_BUILD_ASSERT(NB_SMALL_SIZE_CLASSES == 64);
@@ -311,6 +315,7 @@ _PyMem_Initialize(struct _pymem_runtime_state *state)
#endif /* WITH_PYMALLOC */
}
+
#ifdef WITH_PYMALLOC
static int
_PyMem_DebugEnabled(void)
diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj
index ab9fb05ade..423e68c57b 100644
--- a/PCbuild/python.vcxproj
+++ b/PCbuild/python.vcxproj
@@ -57,7 +57,7 @@
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
- <PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>Py_BUILD_CORE;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -113,4 +113,4 @@ $(_PGOPath)
</PropertyGroup>
<WriteLinesToFile File="$(PySourcePath)python.bat" Lines="$(_Content)" Overwrite="true" Condition="'$(_Content)' != '$(_ExistingContent)'" />
</Target>
-</Project> \ No newline at end of file
+</Project>
diff --git a/Parser/pgenmain.c b/Parser/pgenmain.c
index 8f3e2f7c4e..dbdf13440a 100644
--- a/Parser/pgenmain.c
+++ b/Parser/pgenmain.c
@@ -27,13 +27,11 @@
int Py_DebugFlag;
int Py_VerboseFlag;
int Py_IgnoreEnvironmentFlag;
-_PyRuntimeState _PyRuntime = {0, 0};
+_PyRuntimeState _PyRuntime = _PyRuntimeState_INIT;
/* Forward */
grammar *getgrammar(const char *filename);
-void Py_Exit(int) _Py_NO_RETURN;
-
void
Py_Exit(int sts)
{
diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c
index 1069966a18..b8b630cfed 100644
--- a/Programs/_freeze_importlib.c
+++ b/Programs/_freeze_importlib.c
@@ -81,7 +81,10 @@ main(int argc, char *argv[])
Py_SetProgramName(L"./_freeze_importlib");
/* Don't install importlib, since it could execute outdated bytecode. */
- _Py_InitializeEx_Private(1, 0);
+ _PyInitError err = _Py_InitializeEx_Private(1, 0);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_FatalInitError(err);
+ }
if (strstr(inpath, "_external") != NULL) {
is_bootstrap = 0;
diff --git a/Programs/python.c b/Programs/python.c
index 270a11babb..707e38f257 100644
--- a/Programs/python.c
+++ b/Programs/python.c
@@ -1,6 +1,7 @@
/* Minimal main program -- everything is loaded from the library */
#include "Python.h"
+#include "internal/pystate.h"
#include <locale.h>
#ifdef __FreeBSD__
@@ -22,9 +23,16 @@ main(int argc, char **argv)
wchar_t **argv_copy;
/* We need a second copy, as Python might modify the first one. */
wchar_t **argv_copy2;
- int i, res;
+ int i, status;
char *oldloc;
+ _PyInitError err = _PyRuntime_Initialize();
+ if (_Py_INIT_FAILED(err)) {
+ fprintf(stderr, "Fatal Python error: %s\n", err.msg);
+ fflush(stderr);
+ exit(1);
+ }
+
/* Force malloc() allocator to bootstrap Python */
#ifdef Py_DEBUG
(void)_PyMem_SetupAllocators("malloc_debug");
@@ -88,7 +96,7 @@ main(int argc, char **argv)
setlocale(LC_ALL, oldloc);
PyMem_RawFree(oldloc);
- res = Py_Main(argc, argv_copy);
+ status = Py_Main(argc, argv_copy);
/* Force again malloc() allocator to release memory blocks allocated
before Py_Main() */
@@ -103,6 +111,6 @@ main(int argc, char **argv)
}
PyMem_RawFree(argv_copy);
PyMem_RawFree(argv_copy2);
- return res;
+ return status;
}
#endif
diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c
index 807d6023ce..e667fa93f0 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 769b33d0ee..77602d70fa 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 950c872ccb..fe60844ef1 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 8817be1c41..66cc711137 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 55ff64951b..30f214e93d 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 6dc8e08be7..d786739188 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