]> granicus.if.org Git - python/commitdiff
bpo-36763: Rework _PyInitError API (GH-13031)
authorVictor Stinner <vstinner@redhat.com>
Wed, 1 May 2019 03:35:33 +0000 (05:35 +0200)
committerGitHub <noreply@github.com>
Wed, 1 May 2019 03:35:33 +0000 (05:35 +0200)
* 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
Modules/getpath.c
Modules/main.c
Python/bootstrap_hash.c
Python/coreconfig.c
Python/frozenmain.c
Python/preconfig.c
Python/pylifecycle.c

index ed2f09f933b23a4ffea458dc9b78dda0b2de5fd2..5743bf5d0fa4acf1bf0352f1f73c0bcaa8273fbc 100644 (file)
@@ -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 ------------------------------------------------ */
 
index dd188c612893a9e839ff98ffae7906f99d34aaee..3991ad719c1ed4f8b79f11ffe84036208f1d5288 100644 (file)
@@ -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 */
index 68f0b99c9fbbf407703ed5c1444f6f5c405bd6bd..575683cd7f889f118137d7a8fb0ab43a11337a94 100644 (file)
@@ -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. */
index 35d9b7f24a912f3a2b61e66a30cd46f830539003..dd752b86094d4ba0b6bd96d196ff35a5b77b2cc4 100644 (file)
@@ -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();
index 750676a4731c457143b31ad89f9ea3ab604d94fc..4bfe745ce449d0600b8b1afff289628566648442 100644 (file)
@@ -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);
index 6554aa75b038f8a063d70ec8994a4a8cbd3f55aa..a777576ad78c8cb3e1e9df003058bc37266311c5 100644 (file)
@@ -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;
index 78377cf6e3a26a724bd8f326a1344e0f5c99e543..108cbc6660617631e38d074faaf1993beef7de7a 100644 (file)
@@ -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 */
index 185d4066e50b1c11697004e2eecfc11251203f0f..c874a509aa559e818f57cb2ee28c94c87afbe429 100644 (file)
@@ -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);
     }
 }