From db7197543112954b0912e3d46e39fefcb1c3b950 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 1 May 2019 05:35:33 +0200 Subject: bpo-36763: Rework _PyInitError API (GH-13031) * Remove _PyInitError.user_err field and _Py_INIT_USER_ERR() macro: use _Py_INIT_ERR() instead. _Py_ExitInitError() now longer calls abort() on error: exit with exit code 1 instead. * Add _PyInitError._type private field. * exitcode field type is now unsigned int on Windows. * Rename prefix field to _func. * Rename msg field to err_msg. --- Include/cpython/coreconfig.h | 43 ++++++++++++++++++++++++++++--------------- Modules/getpath.c | 4 ++-- Modules/main.c | 2 +- Python/bootstrap_hash.c | 4 ++-- Python/coreconfig.c | 17 ++++++++--------- Python/frozenmain.c | 4 +--- Python/preconfig.c | 10 +++++----- Python/pylifecycle.c | 18 ++++++++++-------- 8 files changed, 57 insertions(+), 45 deletions(-) diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h index ed2f09f..5743bf5 100644 --- a/Include/cpython/coreconfig.h +++ b/Include/cpython/coreconfig.h @@ -8,10 +8,18 @@ extern "C" { /* --- _PyInitError ----------------------------------------------- */ typedef struct { - const char *prefix; - const char *msg; - int user_err; + enum { + _Py_INIT_ERR_TYPE_OK=0, + _Py_INIT_ERR_TYPE_ERROR=1, + _Py_INIT_ERR_TYPE_EXIT=2 + } _type; + const char *_func; + const char *err_msg; +#ifdef MS_WINDOWS + unsigned int exitcode; +#else int exitcode; +#endif } _PyInitError; /* Almost all errors causing Python initialization to fail */ @@ -23,20 +31,25 @@ typedef struct { #endif #define _Py_INIT_OK() \ - (_PyInitError){.prefix = NULL, .msg = NULL, .user_err = 0, .exitcode = -1} -#define _Py_INIT_ERR(MSG) \ - (_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 0, .exitcode = -1} -/* 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, .exitcode = -1} -#define _Py_INIT_NO_MEMORY() _Py_INIT_USER_ERR("memory allocation failed") + (_PyInitError){._type = _Py_INIT_ERR_TYPE_OK,} + /* other fields are set to 0 */ +#define _Py_INIT_ERR(ERR_MSG) \ + (_PyInitError){ \ + ._type = _Py_INIT_ERR_TYPE_ERROR, \ + ._func = _Py_INIT_GET_FUNC(), \ + .err_msg = (ERR_MSG)} + /* other fields are set to 0 */ +#define _Py_INIT_NO_MEMORY() _Py_INIT_ERR("memory allocation failed") #define _Py_INIT_EXIT(EXITCODE) \ - (_PyInitError){.prefix = NULL, .msg = NULL, .user_err = 0, .exitcode = (EXITCODE)} -#define _Py_INIT_HAS_EXITCODE(err) \ - (err.exitcode != -1) + (_PyInitError){ \ + ._type = _Py_INIT_ERR_TYPE_EXIT, \ + .exitcode = (EXITCODE)} +#define _Py_INIT_IS_ERROR(err) \ + (err._type == _Py_INIT_ERR_TYPE_ERROR) +#define _Py_INIT_IS_EXIT(err) \ + (err._type == _Py_INIT_ERR_TYPE_EXIT) #define _Py_INIT_FAILED(err) \ - (err.msg != NULL || _Py_INIT_HAS_EXITCODE(err)) + (err._type != _Py_INIT_ERR_TYPE_OK) /* --- _PyWstrList ------------------------------------------------ */ diff --git a/Modules/getpath.c b/Modules/getpath.c index dd188c6..3991ad7 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -114,10 +114,10 @@ extern "C" { #define DECODE_LOCALE_ERR(NAME, LEN) \ ((LEN) == (size_t)-2) \ - ? _Py_INIT_USER_ERR("cannot decode " NAME) \ + ? _Py_INIT_ERR("cannot decode " NAME) \ : _Py_INIT_NO_MEMORY() -#define PATHLEN_ERR() _Py_INIT_USER_ERR("path configuration: path too long") +#define PATHLEN_ERR() _Py_INIT_ERR("path configuration: path too long") typedef struct { wchar_t *path_env; /* PATH environment variable */ diff --git a/Modules/main.c b/Modules/main.c index 68f0b99..575683c 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -570,7 +570,7 @@ exit_sigint(void) static void _Py_NO_RETURN pymain_exit_error(_PyInitError err) { - if (_Py_INIT_HAS_EXITCODE(err)) { + if (_Py_INIT_IS_EXIT(err)) { /* If it's an error rather than a regular exit, leave Python runtime alive: _Py_ExitInitError() uses the current exception and use sys.stdout in this case. */ diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c index 35d9b7f..dd752b8 100644 --- a/Python/bootstrap_hash.c +++ b/Python/bootstrap_hash.c @@ -578,8 +578,8 @@ _Py_HashRandomization_Init(const _PyCoreConfig *config) pyurandom() is non-blocking mode (blocking=0): see the PEP 524. */ res = pyurandom(secret, secret_size, 0, 0); if (res < 0) { - return _Py_INIT_USER_ERR("failed to get random numbers " - "to initialize Python"); + return _Py_INIT_ERR("failed to get random numbers " + "to initialize Python"); } } return _Py_INIT_OK(); diff --git a/Python/coreconfig.c b/Python/coreconfig.c index 750676a..4bfe745 100644 --- a/Python/coreconfig.c +++ b/Python/coreconfig.c @@ -475,7 +475,7 @@ Py_GetArgcArgv(int *argc, wchar_t ***argv) #define DECODE_LOCALE_ERR(NAME, LEN) \ (((LEN) == -2) \ - ? _Py_INIT_USER_ERR("cannot decode " NAME) \ + ? _Py_INIT_ERR("cannot decode " NAME) \ : _Py_INIT_NO_MEMORY()) /* Free memory allocated in config, but don't clear all attributes */ @@ -1018,8 +1018,8 @@ config_init_hash_seed(_PyCoreConfig *config) || seed > 4294967295UL || (errno == ERANGE && seed == ULONG_MAX)) { - return _Py_INIT_USER_ERR("PYTHONHASHSEED must be \"random\" " - "or an integer in range [0; 4294967295]"); + return _Py_INIT_ERR("PYTHONHASHSEED must be \"random\" " + "or an integer in range [0; 4294967295]"); } /* Use a specific hash */ config->use_hash_seed = 1; @@ -1129,8 +1129,7 @@ config_init_tracemalloc(_PyCoreConfig *config) valid = 0; } if (!valid) { - return _Py_INIT_USER_ERR("PYTHONTRACEMALLOC: invalid number " - "of frames"); + return _Py_INIT_ERR("PYTHONTRACEMALLOC: invalid number of frames"); } config->tracemalloc = nframe; } @@ -1146,8 +1145,8 @@ config_init_tracemalloc(_PyCoreConfig *config) valid = 0; } if (!valid) { - return _Py_INIT_USER_ERR("-X tracemalloc=NFRAME: " - "invalid number of frames"); + return _Py_INIT_ERR("-X tracemalloc=NFRAME: " + "invalid number of frames"); } } else { @@ -1267,8 +1266,8 @@ config_get_locale_encoding(char **locale_encoding) #else const char *encoding = nl_langinfo(CODESET); if (!encoding || encoding[0] == '\0') { - return _Py_INIT_USER_ERR("failed to get the locale encoding: " - "nl_langinfo(CODESET) failed"); + return _Py_INIT_ERR("failed to get the locale encoding: " + "nl_langinfo(CODESET) failed"); } #endif *locale_encoding = _PyMem_RawStrdup(encoding); diff --git a/Python/frozenmain.c b/Python/frozenmain.c index 6554aa7..a777576 100644 --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -18,9 +18,7 @@ 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); + _Py_ExitInitError(err); } const char *p; diff --git a/Python/preconfig.c b/Python/preconfig.c index 78377cf..108cbc6 100644 --- a/Python/preconfig.c +++ b/Python/preconfig.c @@ -7,7 +7,7 @@ #define DECODE_LOCALE_ERR(NAME, LEN) \ (((LEN) == -2) \ - ? _Py_INIT_USER_ERR("cannot decode " NAME) \ + ? _Py_INIT_ERR("cannot decode " NAME) \ : _Py_INIT_NO_MEMORY()) @@ -526,7 +526,7 @@ preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline) config->utf8_mode = 0; } else { - return _Py_INIT_USER_ERR("invalid -X utf8 option value"); + return _Py_INIT_ERR("invalid -X utf8 option value"); } } else { @@ -544,8 +544,8 @@ preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline) config->utf8_mode = 0; } else { - return _Py_INIT_USER_ERR("invalid PYTHONUTF8 environment " - "variable value"); + return _Py_INIT_ERR("invalid PYTHONUTF8 environment " + "variable value"); } return _Py_INIT_OK(); } @@ -831,7 +831,7 @@ _PyPreConfig_SetAllocator(_PyPreConfig *config) PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); if (_PyMem_SetupAllocators(config->allocator) < 0) { - return _Py_INIT_USER_ERR("Unknown PYTHONMALLOC allocator"); + return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator"); } /* Copy the pre-configuration with the new allocator */ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 185d406..c874a50 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1685,7 +1685,7 @@ initsite(void) PyObject *m; m = PyImport_ImportModule("site"); if (m == NULL) { - return _Py_INIT_USER_ERR("Failed to import the site module"); + return _Py_INIT_ERR("Failed to import the site module"); } Py_DECREF(m); return _Py_INIT_OK(); @@ -1872,8 +1872,7 @@ init_sys_streams(PyInterpreterState *interp) struct _Py_stat_struct sb; if (_Py_fstat_noraise(fileno(stdin), &sb) == 0 && S_ISDIR(sb.st_mode)) { - return _Py_INIT_USER_ERR(" is a directory, " - "cannot continue"); + return _Py_INIT_ERR(" is a directory, cannot continue"); } #endif @@ -2181,14 +2180,17 @@ Py_FatalError(const char *msg) void _Py_NO_RETURN _Py_ExitInitError(_PyInitError err) { - if (_Py_INIT_HAS_EXITCODE(err)) { + assert(_Py_INIT_FAILED(err)); + if (_Py_INIT_IS_EXIT(err)) { +#ifdef MS_WINDOWS + ExitProcess(err.exitcode); +#else exit(err.exitcode); +#endif } else { - /* 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); + assert(_Py_INIT_IS_ERROR(err)); + fatal_error(err._func, err.err_msg, 1); } } -- cgit v0.12