summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@redhat.com>2019-05-01 05:35:33 +0200
committerGitHub <noreply@github.com>2019-05-01 05:35:33 +0200
commitdb7197543112954b0912e3d46e39fefcb1c3b950 (patch)
tree0c82232775c6b1a03671054f9e70f2bb99e6adc9
parentc4e671eec20dfcb29b18596a89ef075f826c9f96 (diff)
downloadcpython-git-db7197543112954b0912e3d46e39fefcb1c3b950.tar.gz
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.
-rw-r--r--Include/cpython/coreconfig.h43
-rw-r--r--Modules/getpath.c4
-rw-r--r--Modules/main.c2
-rw-r--r--Python/bootstrap_hash.c4
-rw-r--r--Python/coreconfig.c17
-rw-r--r--Python/frozenmain.c4
-rw-r--r--Python/preconfig.c10
-rw-r--r--Python/pylifecycle.c18
8 files changed, 57 insertions, 45 deletions
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index ed2f09f933..5743bf5d0f 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 dd188c6128..3991ad719c 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 68f0b99c9f..575683cd7f 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 35d9b7f24a..dd752b8609 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 750676a473..4bfe745ce4 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 6554aa75b0..a777576ad7 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 78377cf6e3..108cbc6660 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 185d4066e5..c874a509aa 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("<stdin> is a directory, "
- "cannot continue");
+ return _Py_INIT_ERR("<stdin> 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);
}
}