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.
This commit is contained in:
parent
c4e671eec2
commit
db71975431
|
@ -8,10 +8,18 @@ extern "C" {
|
||||||
/* --- _PyInitError ----------------------------------------------- */
|
/* --- _PyInitError ----------------------------------------------- */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *prefix;
|
enum {
|
||||||
const char *msg;
|
_Py_INIT_ERR_TYPE_OK=0,
|
||||||
int user_err;
|
_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;
|
int exitcode;
|
||||||
|
#endif
|
||||||
} _PyInitError;
|
} _PyInitError;
|
||||||
|
|
||||||
/* Almost all errors causing Python initialization to fail */
|
/* Almost all errors causing Python initialization to fail */
|
||||||
|
@ -23,20 +31,25 @@ typedef struct {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define _Py_INIT_OK() \
|
#define _Py_INIT_OK() \
|
||||||
(_PyInitError){.prefix = NULL, .msg = NULL, .user_err = 0, .exitcode = -1}
|
(_PyInitError){._type = _Py_INIT_ERR_TYPE_OK,}
|
||||||
#define _Py_INIT_ERR(MSG) \
|
/* other fields are set to 0 */
|
||||||
(_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 0, .exitcode = -1}
|
#define _Py_INIT_ERR(ERR_MSG) \
|
||||||
/* Error that can be fixed by the user like invalid input parameter.
|
(_PyInitError){ \
|
||||||
Don't abort() the process on such error. */
|
._type = _Py_INIT_ERR_TYPE_ERROR, \
|
||||||
#define _Py_INIT_USER_ERR(MSG) \
|
._func = _Py_INIT_GET_FUNC(), \
|
||||||
(_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 1, .exitcode = -1}
|
.err_msg = (ERR_MSG)}
|
||||||
#define _Py_INIT_NO_MEMORY() _Py_INIT_USER_ERR("memory allocation failed")
|
/* other fields are set to 0 */
|
||||||
|
#define _Py_INIT_NO_MEMORY() _Py_INIT_ERR("memory allocation failed")
|
||||||
#define _Py_INIT_EXIT(EXITCODE) \
|
#define _Py_INIT_EXIT(EXITCODE) \
|
||||||
(_PyInitError){.prefix = NULL, .msg = NULL, .user_err = 0, .exitcode = (EXITCODE)}
|
(_PyInitError){ \
|
||||||
#define _Py_INIT_HAS_EXITCODE(err) \
|
._type = _Py_INIT_ERR_TYPE_EXIT, \
|
||||||
(err.exitcode != -1)
|
.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) \
|
#define _Py_INIT_FAILED(err) \
|
||||||
(err.msg != NULL || _Py_INIT_HAS_EXITCODE(err))
|
(err._type != _Py_INIT_ERR_TYPE_OK)
|
||||||
|
|
||||||
/* --- _PyWstrList ------------------------------------------------ */
|
/* --- _PyWstrList ------------------------------------------------ */
|
||||||
|
|
||||||
|
|
|
@ -114,10 +114,10 @@ extern "C" {
|
||||||
|
|
||||||
#define DECODE_LOCALE_ERR(NAME, LEN) \
|
#define DECODE_LOCALE_ERR(NAME, LEN) \
|
||||||
((LEN) == (size_t)-2) \
|
((LEN) == (size_t)-2) \
|
||||||
? _Py_INIT_USER_ERR("cannot decode " NAME) \
|
? _Py_INIT_ERR("cannot decode " NAME) \
|
||||||
: _Py_INIT_NO_MEMORY()
|
: _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 {
|
typedef struct {
|
||||||
wchar_t *path_env; /* PATH environment variable */
|
wchar_t *path_env; /* PATH environment variable */
|
||||||
|
|
|
@ -570,7 +570,7 @@ exit_sigint(void)
|
||||||
static void _Py_NO_RETURN
|
static void _Py_NO_RETURN
|
||||||
pymain_exit_error(_PyInitError err)
|
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
|
/* If it's an error rather than a regular exit, leave Python runtime
|
||||||
alive: _Py_ExitInitError() uses the current exception and use
|
alive: _Py_ExitInitError() uses the current exception and use
|
||||||
sys.stdout in this case. */
|
sys.stdout in this case. */
|
||||||
|
|
|
@ -578,8 +578,8 @@ _Py_HashRandomization_Init(const _PyCoreConfig *config)
|
||||||
pyurandom() is non-blocking mode (blocking=0): see the PEP 524. */
|
pyurandom() is non-blocking mode (blocking=0): see the PEP 524. */
|
||||||
res = pyurandom(secret, secret_size, 0, 0);
|
res = pyurandom(secret, secret_size, 0, 0);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
return _Py_INIT_USER_ERR("failed to get random numbers "
|
return _Py_INIT_ERR("failed to get random numbers "
|
||||||
"to initialize Python");
|
"to initialize Python");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _Py_INIT_OK();
|
return _Py_INIT_OK();
|
||||||
|
|
|
@ -475,7 +475,7 @@ Py_GetArgcArgv(int *argc, wchar_t ***argv)
|
||||||
|
|
||||||
#define DECODE_LOCALE_ERR(NAME, LEN) \
|
#define DECODE_LOCALE_ERR(NAME, LEN) \
|
||||||
(((LEN) == -2) \
|
(((LEN) == -2) \
|
||||||
? _Py_INIT_USER_ERR("cannot decode " NAME) \
|
? _Py_INIT_ERR("cannot decode " NAME) \
|
||||||
: _Py_INIT_NO_MEMORY())
|
: _Py_INIT_NO_MEMORY())
|
||||||
|
|
||||||
/* Free memory allocated in config, but don't clear all attributes */
|
/* Free memory allocated in config, but don't clear all attributes */
|
||||||
|
@ -1018,8 +1018,8 @@ config_init_hash_seed(_PyCoreConfig *config)
|
||||||
|| seed > 4294967295UL
|
|| seed > 4294967295UL
|
||||||
|| (errno == ERANGE && seed == ULONG_MAX))
|
|| (errno == ERANGE && seed == ULONG_MAX))
|
||||||
{
|
{
|
||||||
return _Py_INIT_USER_ERR("PYTHONHASHSEED must be \"random\" "
|
return _Py_INIT_ERR("PYTHONHASHSEED must be \"random\" "
|
||||||
"or an integer in range [0; 4294967295]");
|
"or an integer in range [0; 4294967295]");
|
||||||
}
|
}
|
||||||
/* Use a specific hash */
|
/* Use a specific hash */
|
||||||
config->use_hash_seed = 1;
|
config->use_hash_seed = 1;
|
||||||
|
@ -1129,8 +1129,7 @@ config_init_tracemalloc(_PyCoreConfig *config)
|
||||||
valid = 0;
|
valid = 0;
|
||||||
}
|
}
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
return _Py_INIT_USER_ERR("PYTHONTRACEMALLOC: invalid number "
|
return _Py_INIT_ERR("PYTHONTRACEMALLOC: invalid number of frames");
|
||||||
"of frames");
|
|
||||||
}
|
}
|
||||||
config->tracemalloc = nframe;
|
config->tracemalloc = nframe;
|
||||||
}
|
}
|
||||||
|
@ -1146,8 +1145,8 @@ config_init_tracemalloc(_PyCoreConfig *config)
|
||||||
valid = 0;
|
valid = 0;
|
||||||
}
|
}
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
return _Py_INIT_USER_ERR("-X tracemalloc=NFRAME: "
|
return _Py_INIT_ERR("-X tracemalloc=NFRAME: "
|
||||||
"invalid number of frames");
|
"invalid number of frames");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1267,8 +1266,8 @@ config_get_locale_encoding(char **locale_encoding)
|
||||||
#else
|
#else
|
||||||
const char *encoding = nl_langinfo(CODESET);
|
const char *encoding = nl_langinfo(CODESET);
|
||||||
if (!encoding || encoding[0] == '\0') {
|
if (!encoding || encoding[0] == '\0') {
|
||||||
return _Py_INIT_USER_ERR("failed to get the locale encoding: "
|
return _Py_INIT_ERR("failed to get the locale encoding: "
|
||||||
"nl_langinfo(CODESET) failed");
|
"nl_langinfo(CODESET) failed");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
*locale_encoding = _PyMem_RawStrdup(encoding);
|
*locale_encoding = _PyMem_RawStrdup(encoding);
|
||||||
|
|
|
@ -18,9 +18,7 @@ Py_FrozenMain(int argc, char **argv)
|
||||||
{
|
{
|
||||||
_PyInitError err = _PyRuntime_Initialize();
|
_PyInitError err = _PyRuntime_Initialize();
|
||||||
if (_Py_INIT_FAILED(err)) {
|
if (_Py_INIT_FAILED(err)) {
|
||||||
fprintf(stderr, "Fatal Python error: %s\n", err.msg);
|
_Py_ExitInitError(err);
|
||||||
fflush(stderr);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#define DECODE_LOCALE_ERR(NAME, LEN) \
|
#define DECODE_LOCALE_ERR(NAME, LEN) \
|
||||||
(((LEN) == -2) \
|
(((LEN) == -2) \
|
||||||
? _Py_INIT_USER_ERR("cannot decode " NAME) \
|
? _Py_INIT_ERR("cannot decode " NAME) \
|
||||||
: _Py_INIT_NO_MEMORY())
|
: _Py_INIT_NO_MEMORY())
|
||||||
|
|
||||||
|
|
||||||
|
@ -526,7 +526,7 @@ preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline)
|
||||||
config->utf8_mode = 0;
|
config->utf8_mode = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return _Py_INIT_USER_ERR("invalid -X utf8 option value");
|
return _Py_INIT_ERR("invalid -X utf8 option value");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -544,8 +544,8 @@ preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline)
|
||||||
config->utf8_mode = 0;
|
config->utf8_mode = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return _Py_INIT_USER_ERR("invalid PYTHONUTF8 environment "
|
return _Py_INIT_ERR("invalid PYTHONUTF8 environment "
|
||||||
"variable value");
|
"variable value");
|
||||||
}
|
}
|
||||||
return _Py_INIT_OK();
|
return _Py_INIT_OK();
|
||||||
}
|
}
|
||||||
|
@ -831,7 +831,7 @@ _PyPreConfig_SetAllocator(_PyPreConfig *config)
|
||||||
PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
||||||
|
|
||||||
if (_PyMem_SetupAllocators(config->allocator) < 0) {
|
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 */
|
/* Copy the pre-configuration with the new allocator */
|
||||||
|
|
|
@ -1685,7 +1685,7 @@ initsite(void)
|
||||||
PyObject *m;
|
PyObject *m;
|
||||||
m = PyImport_ImportModule("site");
|
m = PyImport_ImportModule("site");
|
||||||
if (m == NULL) {
|
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);
|
Py_DECREF(m);
|
||||||
return _Py_INIT_OK();
|
return _Py_INIT_OK();
|
||||||
|
@ -1872,8 +1872,7 @@ init_sys_streams(PyInterpreterState *interp)
|
||||||
struct _Py_stat_struct sb;
|
struct _Py_stat_struct sb;
|
||||||
if (_Py_fstat_noraise(fileno(stdin), &sb) == 0 &&
|
if (_Py_fstat_noraise(fileno(stdin), &sb) == 0 &&
|
||||||
S_ISDIR(sb.st_mode)) {
|
S_ISDIR(sb.st_mode)) {
|
||||||
return _Py_INIT_USER_ERR("<stdin> is a directory, "
|
return _Py_INIT_ERR("<stdin> is a directory, cannot continue");
|
||||||
"cannot continue");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2181,14 +2180,17 @@ Py_FatalError(const char *msg)
|
||||||
void _Py_NO_RETURN
|
void _Py_NO_RETURN
|
||||||
_Py_ExitInitError(_PyInitError err)
|
_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);
|
exit(err.exitcode);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* On "user" error: exit with status 1.
|
assert(_Py_INIT_IS_ERROR(err));
|
||||||
For all other errors, call abort(). */
|
fatal_error(err._func, err.err_msg, 1);
|
||||||
int status = err.user_err ? 1 : -1;
|
|
||||||
fatal_error(err.prefix, err.msg, status);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue