Issue #5319: New Py_FinalizeEx() API to exit with status 120 on failure · python/cpython@b4ce1fc · GitHub
Skip to content

Commit b4ce1fc

Browse files
committed
Issue #5319: New Py_FinalizeEx() API to exit with status 120 on failure
1 parent 92d5fba commit b4ce1fc

18 files changed

Lines changed: 120 additions & 58 deletions

File tree

Doc/c-api/init.rst

Lines changed: 21 additions & 12 deletions

Doc/c-api/intro.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -578,9 +578,9 @@ Sometimes, it is desirable to "uninitialize" Python. For instance, the
578578
application may want to start over (make another call to
579579
:c:func:`Py_Initialize`) or the application is simply done with its use of
580580
Python and wants to free memory allocated by Python. This can be accomplished
581-
by calling :c:func:`Py_Finalize`. The function :c:func:`Py_IsInitialized` returns
581+
by calling :c:func:`Py_FinalizeEx`. The function :c:func:`Py_IsInitialized` returns
582582
true if Python is currently in the initialized state. More information about
583-
these functions is given in a later chapter. Notice that :c:func:`Py_Finalize`
583+
these functions is given in a later chapter. Notice that :c:func:`Py_FinalizeEx`
584584
does *not* free all memory allocated by the Python interpreter, e.g. memory
585585
allocated by extension modules currently cannot be released.
586586

Doc/c-api/sys.rst

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,20 +212,24 @@ Process Control
212212
.. c:function:: void Py_Exit(int status)
213213
214214
.. index::
215-
single: Py_Finalize()
215+
single: Py_FinalizeEx()
216216
single: exit()
217217
218-
Exit the current process. This calls :c:func:`Py_Finalize` and then calls the
219-
standard C library function ``exit(status)``.
218+
Exit the current process. This calls :c:func:`Py_FinalizeEx` and then calls the
219+
standard C library function ``exit(status)``. If :c:func:`Py_FinalizeEx`
220+
indicates an error, the exit status is set to 120.
221+
222+
.. versionchanged:: 3.6
223+
Errors from finalization no longer ignored.
220224
221225
222226
.. c:function:: int Py_AtExit(void (*func) ())
223227
224228
.. index::
225-
single: Py_Finalize()
229+
single: Py_FinalizeEx()
226230
single: cleanup functions
227231
228-
Register a cleanup function to be called by :c:func:`Py_Finalize`. The cleanup
232+
Register a cleanup function to be called by :c:func:`Py_FinalizeEx`. The cleanup
229233
function will be called with no arguments and should return no value. At most
230234
32 cleanup functions can be registered. When the registration is successful,
231235
:c:func:`Py_AtExit` returns ``0``; on failure, it returns ``-1``. The cleanup

Doc/extending/embedding.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ perform some operation on a file. ::
6767
Py_Initialize();
6868
PyRun_SimpleString("from time import time,ctime\n"
6969
"print('Today is', ctime(time()))\n");
70-
Py_Finalize();
70+
if (Py_FinalizeEx() < 0) {
71+
exit(120);
72+
}
7173
PyMem_RawFree(program);
7274
return 0;
7375
}
@@ -76,7 +78,7 @@ The :c:func:`Py_SetProgramName` function should be called before
7678
:c:func:`Py_Initialize` to inform the interpreter about paths to Python run-time
7779
libraries. Next, the Python interpreter is initialized with
7880
:c:func:`Py_Initialize`, followed by the execution of a hard-coded Python script
79-
that prints the date and time. Afterwards, the :c:func:`Py_Finalize` call shuts
81+
that prints the date and time. Afterwards, the :c:func:`Py_FinalizeEx` call shuts
8082
the interpreter down, followed by the end of the program. In a real program,
8183
you may want to get the Python script from another source, perhaps a text-editor
8284
routine, a file, or a database. Getting the Python code from a file can better

Doc/includes/run-func.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ main(int argc, char *argv[])
6363
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
6464
return 1;
6565
}
66-
Py_Finalize();
66+
if (Py_FinalizeEx() < 0) {
67+
return 120;
68+
}
6769
return 0;
6870
}

Doc/library/sys.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ always available.
255255
(defaulting to zero), or another type of object. If it is an integer, zero
256256
is considered "successful termination" and any nonzero value is considered
257257
"abnormal termination" by shells and the like. Most systems require it to be
258-
in the range 0-127, and produce undefined results otherwise. Some systems
258+
in the range 0--127, and produce undefined results otherwise. Some systems
259259
have a convention for assigning specific meanings to specific exit codes, but
260260
these are generally underdeveloped; Unix programs generally use 2 for command
261261
line syntax errors and 1 for all other kind of errors. If another type of
@@ -268,6 +268,11 @@ always available.
268268
the process when called from the main thread, and the exception is not
269269
intercepted.
270270

271+
.. versionchanged:: 3.6
272+
If an error occurs in the cleanup after the Python interpreter
273+
has caught :exc:`SystemExit` (such as an error flushing buffered data
274+
in the standard streams), the exit status is changed to 120.
275+
271276

272277
.. data:: flags
273278

Doc/whatsnew/3.6.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ Optimizations
171171
Build and C API Changes
172172
=======================
173173

174-
* None yet.
174+
* New :c:func:`Py_FinalizeEx` API which indicates if flushing buffered data
175+
failed (:issue:`5319`).
175176

176177

177178
Deprecated
@@ -247,4 +248,5 @@ Changes in the Python API
247248
Changes in the C API
248249
--------------------
249250

250-
* None yet.
251+
* :c:func:`Py_Exit` (and the main interpreter) now override the exit status
252+
with 120 if flushing buffered data failed. See :issue:`5319`.

Include/pylifecycle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ PyAPI_FUNC(void) Py_InitializeEx(int);
2727
PyAPI_FUNC(void) _Py_InitializeEx_Private(int, int);
2828
#endif
2929
PyAPI_FUNC(void) Py_Finalize(void);
30+
PyAPI_FUNC(int) Py_FinalizeEx(void);
3031
PyAPI_FUNC(int) Py_IsInitialized(void);
3132
PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void);
3233
PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *);

Lib/test/test_cmd_line.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,9 @@ def test_stdout_flush_at_shutdown(self):
348348
test.support.SuppressCrashReport().__enter__()
349349
sys.stdout.write('x')
350350
os.close(sys.stdout.fileno())"""
351-
rc, out, err = assert_python_ok('-c', code)
351+
rc, out, err = assert_python_failure('-c', code)
352352
self.assertEqual(b'', out)
353+
self.assertEqual(120, rc)
353354
self.assertRegex(err.decode('ascii', 'ignore'),
354355
'Exception ignored in.*\nOSError: .*')
355356

Misc/NEWS

Lines changed: 3 additions & 0 deletions

0 commit comments

Comments
 (0)