]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-114570: Add PythonFinalizationError exception (#115352)
authorVictor Stinner <vstinner@python.org>
Wed, 14 Feb 2024 22:35:06 +0000 (23:35 +0100)
committerGitHub <noreply@github.com>
Wed, 14 Feb 2024 22:35:06 +0000 (23:35 +0100)
Add PythonFinalizationError exception. This exception derived from
RuntimeError is raised when an operation is blocked during the Python
finalization.

The following functions now raise PythonFinalizationError, instead of
RuntimeError:

* _thread.start_new_thread()
* subprocess.Popen
* os.fork()
* os.fork1()
* os.forkpty()

Morever, _winapi.Overlapped finalizer now logs an unraisable
PythonFinalizationError, instead of an unraisable RuntimeError.

13 files changed:
Doc/library/exceptions.rst
Doc/library/sys.rst
Doc/whatsnew/3.13.rst
Include/cpython/pyerrors.h
Lib/test/exception_hierarchy.txt
Lib/test/test_pickle.py
Misc/NEWS.d/next/Core and Builtins/2024-02-12-17-18-26.gh-issue-114570.BzwMlJ.rst [new file with mode: 0644]
Modules/_posixsubprocess.c
Modules/_threadmodule.c
Modules/_winapi.c
Modules/posixmodule.c
Objects/exceptions.c
Tools/c-analyzer/cpython/globals-to-fix.tsv

index 3191315049ad5a43ea9e7e3bd68322b1ce2337c0..88417b40e4aa7f9cb2b33a7d45c97eafe1644b3a 100644 (file)
@@ -416,6 +416,24 @@ The following exceptions are the exceptions that are usually raised.
    handling in C, most floating point operations are not checked.
 
 
+.. exception:: PythonFinalizationError
+
+   This exception is derived from :exc:`RuntimeError`.  It is raised when
+   an operation is blocked during interpreter shutdown also known as
+   :term:`Python finalization <interpreter shutdown>`.
+
+   Examples of operations which can be blocked with a
+   :exc:`PythonFinalizationError` during the Python finalization:
+
+   * Creating a new Python thread.
+   * :func:`os.fork`.
+
+   See also the :func:`sys.is_finalizing` function.
+
+   .. versionadded:: 3.13
+      Previously, a plain :exc:`RuntimeError` was raised.
+
+
 .. exception:: RecursionError
 
    This exception is derived from :exc:`RuntimeError`.  It is raised when the
index ad8857fc2807f7078385018f3f5108a4336eb43f..351c44b1915159ff8927b5bb998fbc373a25aa81 100644 (file)
@@ -1202,6 +1202,8 @@ always available.
    Return :const:`True` if the main Python interpreter is
    :term:`shutting down <interpreter shutdown>`. Return :const:`False` otherwise.
 
+   See also the :exc:`PythonFinalizationError` exception.
+
    .. versionadded:: 3.5
 
 .. data:: last_exc
index b14fb4e5392a2c38bef20b57bf1ddc77163513d3..1e0764144a2855389f81dcdcfaf9597706153679 100644 (file)
@@ -160,6 +160,21 @@ Other Language Changes
   (Contributed by Levi Sabah, Zackery Spytz and Hugo van Kemenade in
   :gh:`73965`.)
 
+* Add :exc:`PythonFinalizationError` exception. This exception derived from
+  :exc:`RuntimeError` is raised when an operation is blocked during
+  the :term:`Python finalization <interpreter shutdown>`.
+
+  The following functions now raise PythonFinalizationError, instead of
+  :exc:`RuntimeError`:
+
+  * :func:`_thread.start_new_thread`.
+  * :class:`subprocess.Popen`.
+  * :func:`os.fork`.
+  * :func:`os.forkpty`.
+
+  (Contributed by Victor Stinner in :gh:`114570`.)
+
+
 New Modules
 ===========
 
index 479b908fb7058ac5e70e2a3f25114df027ec0381..32c5884cd21341c1b8ac7807f9c86ba0b350d535 100644 (file)
@@ -122,4 +122,6 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalErrorFunc(
 
 PyAPI_FUNC(void) PyErr_FormatUnraisable(const char *, ...);
 
+PyAPI_DATA(PyObject *) PyExc_PythonFinalizationError;
+
 #define Py_FatalError(message) _Py_FatalErrorFunc(__func__, (message))
index 217ee15d4c8af54322e860c6e5cac593c9623462..65f54859e2a21d0328edbe0adfd0b191492302da 100644 (file)
@@ -40,6 +40,7 @@ BaseException
       ├── ReferenceError
       ├── RuntimeError
       │    ├── NotImplementedError
+      │    ├── PythonFinalizationError
       │    └── RecursionError
       ├── StopAsyncIteration
       ├── StopIteration
index 5e187e5189d11795467654ecefe8f6e3409aee6f..19f977971570b76fe81f42a5e8aadaacc8ca2ca8 100644 (file)
@@ -564,6 +564,7 @@ class CompatPickleTests(unittest.TestCase):
                 if exc in (BlockingIOError,
                            ResourceWarning,
                            StopAsyncIteration,
+                           PythonFinalizationError,
                            RecursionError,
                            EncodingWarning,
                            BaseExceptionGroup,
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-02-12-17-18-26.gh-issue-114570.BzwMlJ.rst b/Misc/NEWS.d/next/Core and Builtins/2024-02-12-17-18-26.gh-issue-114570.BzwMlJ.rst
new file mode 100644 (file)
index 0000000..828d47d
--- /dev/null
@@ -0,0 +1,3 @@
+Add :exc:`PythonFinalizationError` exception. This exception derived from
+:exc:`RuntimeError` is raised when an operation is blocked during the
+:term:`Python finalization <interpreter shutdown>`. Patch by Victor Stinner.
index aa1a300e4378dd9dd926f0b53fd24d07855e3010..bcbbe70680b8e763e4585bda52358b24fac50b0e 100644 (file)
@@ -1032,7 +1032,7 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args,
 
     PyInterpreterState *interp = _PyInterpreterState_GET();
     if ((preexec_fn != Py_None) && interp->finalizing) {
-        PyErr_SetString(PyExc_RuntimeError,
+        PyErr_SetString(PyExc_PythonFinalizationError,
                         "preexec_fn not supported at interpreter shutdown");
         return NULL;
     }
index d7840eaf45e8d69445bce94b5d59370063e94c65..da6a8bc7b120fedd9c396892bc8ef43ae60f292e 100644 (file)
@@ -1304,7 +1304,7 @@ do_start_new_thread(thread_module_state* state,
         return -1;
     }
     if (interp->finalizing) {
-        PyErr_SetString(PyExc_RuntimeError,
+        PyErr_SetString(PyExc_PythonFinalizationError,
                         "can't create new thread at interpreter shutdown");
         return -1;
     }
index 83a4ccd4802ae01eb718bdc8c4c228a6e226fa99..8f9b8520bb3f349b838fdae53c9af69e59776e61 100644 (file)
@@ -139,7 +139,7 @@ overlapped_dealloc(OverlappedObject *self)
         {
             /* The operation is still pending -- give a warning.  This
                will probably only happen on Windows XP. */
-            PyErr_SetString(PyExc_RuntimeError,
+            PyErr_SetString(PyExc_PythonFinalizationError,
                             "I/O operations still in flight while destroying "
                             "Overlapped object, the process may crash");
             PyErr_WriteUnraisable(NULL);
index ef6d65623bf038817e7284a35fbcceb8a5b2355b..958b5a5e6e240663ddbdd385ae8fae0add77dfa3 100644 (file)
@@ -7841,7 +7841,7 @@ os_fork1_impl(PyObject *module)
 
     PyInterpreterState *interp = _PyInterpreterState_GET();
     if (interp->finalizing) {
-        PyErr_SetString(PyExc_RuntimeError,
+        PyErr_SetString(PyExc_PythonFinalizationError,
                         "can't fork at interpreter shutdown");
         return NULL;
     }
@@ -7885,7 +7885,7 @@ os_fork_impl(PyObject *module)
     pid_t pid;
     PyInterpreterState *interp = _PyInterpreterState_GET();
     if (interp->finalizing) {
-        PyErr_SetString(PyExc_RuntimeError,
+        PyErr_SetString(PyExc_PythonFinalizationError,
                         "can't fork at interpreter shutdown");
         return NULL;
     }
@@ -8718,7 +8718,7 @@ os_forkpty_impl(PyObject *module)
 
     PyInterpreterState *interp = _PyInterpreterState_GET();
     if (interp->finalizing) {
-        PyErr_SetString(PyExc_RuntimeError,
+        PyErr_SetString(PyExc_PythonFinalizationError,
                         "can't fork at interpreter shutdown");
         return NULL;
     }
index 3df3a9b3b1a2530a90599dd0decbbd0a4f569739..63c461d34fb4ff275765e509cbb34ddbf21c6685 100644 (file)
@@ -2177,6 +2177,10 @@ SimpleExtendsException(PyExc_Exception, RuntimeError,
 SimpleExtendsException(PyExc_RuntimeError, RecursionError,
                        "Recursion limit exceeded.");
 
+// PythonFinalizationError extends RuntimeError
+SimpleExtendsException(PyExc_RuntimeError, PythonFinalizationError,
+                       "Operation blocked during Python finalization.");
+
 /*
  *    NotImplementedError extends RuntimeError
  */
@@ -3641,6 +3645,7 @@ static struct static_exception static_exceptions[] = {
     ITEM(KeyError),  // base: LookupError(Exception)
     ITEM(ModuleNotFoundError), // base: ImportError(Exception)
     ITEM(NotImplementedError),  // base: RuntimeError(Exception)
+    ITEM(PythonFinalizationError),  // base: RuntimeError(Exception)
     ITEM(RecursionError),  // base: RuntimeError(Exception)
     ITEM(UnboundLocalError), // base: NameError(Exception)
     ITEM(UnicodeError),  // base: ValueError(Exception)
index 5c5016f71371640d4e8125b2f569d13324be6ffd..45119664af4362a23c10b6d6671528f8b1bbe7ce 100644 (file)
@@ -189,6 +189,7 @@ Objects/exceptions.c        -       _PyExc_ProcessLookupError       -
 Objects/exceptions.c   -       _PyExc_TimeoutError     -
 Objects/exceptions.c   -       _PyExc_EOFError -
 Objects/exceptions.c   -       _PyExc_RuntimeError     -
+Objects/exceptions.c   -       _PyExc_PythonFinalizationError  -
 Objects/exceptions.c   -       _PyExc_RecursionError   -
 Objects/exceptions.c   -       _PyExc_NotImplementedError      -
 Objects/exceptions.c   -       _PyExc_NameError        -
@@ -254,6 +255,7 @@ Objects/exceptions.c        -       PyExc_ProcessLookupError        -
 Objects/exceptions.c   -       PyExc_TimeoutError      -
 Objects/exceptions.c   -       PyExc_EOFError  -
 Objects/exceptions.c   -       PyExc_RuntimeError      -
+Objects/exceptions.c   -       PyExc_PythonFinalizationError   -
 Objects/exceptions.c   -       PyExc_RecursionError    -
 Objects/exceptions.c   -       PyExc_NotImplementedError       -
 Objects/exceptions.c   -       PyExc_NameError -