Skip to content

bpo-36763: Rework _PyInitError API #13031

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 28 additions & 15 deletions Include/cpython/coreconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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 ------------------------------------------------ */

Expand Down
4 changes: 2 additions & 2 deletions Modules/getpath.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion Modules/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
4 changes: 2 additions & 2 deletions Python/bootstrap_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
17 changes: 8 additions & 9 deletions Python/coreconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 1 addition & 3 deletions Python/frozenmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 5 additions & 5 deletions Python/preconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -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())


Expand Down Expand Up @@ -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 {
Expand All @@ -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();
}
Expand Down Expand Up @@ -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 */
Expand Down
18 changes: 10 additions & 8 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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);
}
}

Expand Down