Commit dfe88475 authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

bpo-36142: Rework error reporting in pymain_main() (GH-12113)

Add a new _Py_INIT_EXIT() macro to be able to exit Python with an
exitcode using _PyInitError API. Rewrite function calls by
pymain_main() to use _PyInitError.

Changes:

* Remove _PyMain.err and _PyMain.status field
* Add _Py_INIT_EXIT() macro and _PyInitError.exitcode field.
* Rename _Py_FatalInitError() to _Py_ExitInitError().
parent b9f0354e
...@@ -11,6 +11,7 @@ typedef struct { ...@@ -11,6 +11,7 @@ typedef struct {
const char *prefix; const char *prefix;
const char *msg; const char *msg;
int user_err; int user_err;
int exitcode;
} _PyInitError; } _PyInitError;
/* Almost all errors causing Python initialization to fail */ /* Almost all errors causing Python initialization to fail */
...@@ -22,16 +23,18 @@ typedef struct { ...@@ -22,16 +23,18 @@ typedef struct {
#endif #endif
#define _Py_INIT_OK() \ #define _Py_INIT_OK() \
(_PyInitError){.prefix = NULL, .msg = NULL, .user_err = 0} (_PyInitError){.prefix = NULL, .msg = NULL, .user_err = 0, .exitcode = -1}
#define _Py_INIT_ERR(MSG) \ #define _Py_INIT_ERR(MSG) \
(_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 0} (_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. /* Error that can be fixed by the user like invalid input parameter.
Don't abort() the process on such error. */ Don't abort() the process on such error. */
#define _Py_INIT_USER_ERR(MSG) \ #define _Py_INIT_USER_ERR(MSG) \
(_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 1} (_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") #define _Py_INIT_NO_MEMORY() _Py_INIT_USER_ERR("memory allocation failed")
#define _Py_INIT_EXIT(EXITCODE) \
(_PyInitError){.prefix = NULL, .msg = NULL, .user_err = 0, .exitcode = (EXITCODE)}
#define _Py_INIT_FAILED(err) \ #define _Py_INIT_FAILED(err) \
(err.msg != NULL) (err.msg != NULL || err.exitcode != -1)
/* _PyCoreConfig */ /* _PyCoreConfig */
......
...@@ -39,7 +39,7 @@ PyAPI_FUNC(_PyInitError) _Py_InitializeMainInterpreter( ...@@ -39,7 +39,7 @@ PyAPI_FUNC(_PyInitError) _Py_InitializeMainInterpreter(
PyAPI_FUNC(_PyInitError) _Py_InitializeFromConfig( PyAPI_FUNC(_PyInitError) _Py_InitializeFromConfig(
const _PyCoreConfig *config); const _PyCoreConfig *config);
PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalInitError(_PyInitError err); PyAPI_FUNC(void) _Py_NO_RETURN _Py_ExitInitError(_PyInitError err);
/* Py_PyAtExit is for the atexit module, Py_AtExit is for low-level /* Py_PyAtExit is for the atexit module, Py_AtExit is for low-level
* exit functions. * exit functions.
......
This diff is collapsed.
...@@ -89,7 +89,7 @@ main(int argc, char *argv[]) ...@@ -89,7 +89,7 @@ main(int argc, char *argv[])
/* No need to call _PyCoreConfig_Clear() since we didn't allocate any /* No need to call _PyCoreConfig_Clear() since we didn't allocate any
memory: program_name is a constant string. */ memory: program_name is a constant string. */
if (_Py_INIT_FAILED(err)) { if (_Py_INIT_FAILED(err)) {
_Py_FatalInitError(err); _Py_ExitInitError(err);
} }
sprintf(buf, "<frozen %s>", name); sprintf(buf, "<frozen %s>", name);
......
...@@ -553,7 +553,7 @@ static int test_init_from_config(void) ...@@ -553,7 +553,7 @@ static int test_init_from_config(void)
_PyInitError err = _Py_InitializeFromConfig(&config); _PyInitError err = _Py_InitializeFromConfig(&config);
/* Don't call _PyCoreConfig_Clear() since all strings are static */ /* Don't call _PyCoreConfig_Clear() since all strings are static */
if (_Py_INIT_FAILED(err)) { if (_Py_INIT_FAILED(err)) {
_Py_FatalInitError(err); _Py_ExitInitError(err);
} }
dump_config(); dump_config();
Py_Finalize(); Py_Finalize();
...@@ -618,7 +618,7 @@ static int test_init_isolated(void) ...@@ -618,7 +618,7 @@ static int test_init_isolated(void)
test_init_env_putenvs(); test_init_env_putenvs();
_PyInitError err = _Py_InitializeFromConfig(&config); _PyInitError err = _Py_InitializeFromConfig(&config);
if (_Py_INIT_FAILED(err)) { if (_Py_INIT_FAILED(err)) {
_Py_FatalInitError(err); _Py_ExitInitError(err);
} }
dump_config(); dump_config();
Py_Finalize(); Py_Finalize();
...@@ -635,7 +635,7 @@ static int test_init_dev_mode(void) ...@@ -635,7 +635,7 @@ static int test_init_dev_mode(void)
config.program_name = L"./_testembed"; config.program_name = L"./_testembed";
_PyInitError err = _Py_InitializeFromConfig(&config); _PyInitError err = _Py_InitializeFromConfig(&config);
if (_Py_INIT_FAILED(err)) { if (_Py_INIT_FAILED(err)) {
_Py_FatalInitError(err); _Py_ExitInitError(err);
} }
dump_config(); dump_config();
Py_Finalize(); Py_Finalize();
......
...@@ -86,7 +86,7 @@ Py_FrozenMain(int argc, char **argv) ...@@ -86,7 +86,7 @@ Py_FrozenMain(int argc, char **argv)
/* No need to call _PyCoreConfig_Clear() since we didn't allocate any /* No need to call _PyCoreConfig_Clear() since we didn't allocate any
memory: program_name is a constant string. */ memory: program_name is a constant string. */
if (_Py_INIT_FAILED(err)) { if (_Py_INIT_FAILED(err)) {
_Py_FatalInitError(err); _Py_ExitInitError(err);
} }
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
......
...@@ -408,7 +408,7 @@ pathconfig_global_init(void) ...@@ -408,7 +408,7 @@ pathconfig_global_init(void)
error: error:
_PyCoreConfig_Clear(&config); _PyCoreConfig_Clear(&config);
_Py_FatalInitError(err); _Py_ExitInitError(err);
} }
......
...@@ -960,7 +960,7 @@ Py_InitializeEx(int install_sigs) ...@@ -960,7 +960,7 @@ Py_InitializeEx(int install_sigs)
_PyCoreConfig_Clear(&config); _PyCoreConfig_Clear(&config);
if (_Py_INIT_FAILED(err)) { if (_Py_INIT_FAILED(err)) {
_Py_FatalInitError(err); _Py_ExitInitError(err);
} }
} }
...@@ -1432,7 +1432,7 @@ Py_NewInterpreter(void) ...@@ -1432,7 +1432,7 @@ Py_NewInterpreter(void)
PyThreadState *tstate; PyThreadState *tstate;
_PyInitError err = new_interpreter(&tstate); _PyInitError err = new_interpreter(&tstate);
if (_Py_INIT_FAILED(err)) { if (_Py_INIT_FAILED(err)) {
_Py_FatalInitError(err); _Py_ExitInitError(err);
} }
return tstate; return tstate;
...@@ -2073,12 +2073,17 @@ Py_FatalError(const char *msg) ...@@ -2073,12 +2073,17 @@ Py_FatalError(const char *msg)
} }
void _Py_NO_RETURN void _Py_NO_RETURN
_Py_FatalInitError(_PyInitError err) _Py_ExitInitError(_PyInitError err)
{ {
/* On "user" error: exit with status 1. if (err.exitcode >= 0) {
For all other errors, call abort(). */ exit(err.exitcode);
int status = err.user_err ? 1 : -1; }
fatal_error(err.prefix, err.msg, status); 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);
}
} }
/* Clean up and exit */ /* Clean up and exit */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment