# HG changeset patch
# Parent 4e84e45e191b3b063387fdd68075f47f4576e215
Issue #5319: Exit with status 1 if Py_Finalize() fails to flush buffers
diff -r 4e84e45e191b Doc/c-api/init.rst
--- a/Doc/c-api/init.rst Fri Dec 19 11:21:56 2014 -0500
+++ b/Doc/c-api/init.rst Sat Dec 20 08:39:56 2014 +0000
@@ -52,15 +52,19 @@
:c:func:`Py_Initialize` is called again.
-.. c:function:: void Py_Finalize()
+.. c:function:: int Py_Finalize()
Undo all initializations made by :c:func:`Py_Initialize` and subsequent use of
Python/C API functions, and destroy all sub-interpreters (see
:c:func:`Py_NewInterpreter` below) that were created and not yet destroyed since
the last call to :c:func:`Py_Initialize`. Ideally, this frees all memory
allocated by the Python interpreter. This is a no-op when called for a second
- time (without calling :c:func:`Py_Initialize` again first). There is no return
- value; errors during finalization are ignored.
+ time (without calling :c:func:`Py_Initialize` again first). Normally the
+ return value is zero. If there were errors during finalization
+ (flushing buffered data), -1 is returned.
+
+ .. versionchanged:: 3.5
+ Previously the return type was *void*.
This function is provided for a number of reasons. An embedding application
might want to restart Python without having to restart the application itself.
diff -r 4e84e45e191b Doc/c-api/sys.rst
--- a/Doc/c-api/sys.rst Fri Dec 19 11:21:56 2014 -0500
+++ b/Doc/c-api/sys.rst Sat Dec 20 08:39:56 2014 +0000
@@ -216,7 +216,11 @@
single: exit()
Exit the current process. This calls :c:func:`Py_Finalize` and then calls the
- standard C library function ``exit(status)``.
+ standard C library function ``exit(status)``. If :c:func:`Py_Finalize`
+ indicates an error, the exit status is set to 1.
+
+ .. versionchanged: 3.5
+ Errors from finalization no longer ignored.
.. c:function:: int Py_AtExit(void (*func) ())
diff -r 4e84e45e191b Doc/data/refcounts.dat
--- a/Doc/data/refcounts.dat Fri Dec 19 11:21:56 2014 -0500
+++ b/Doc/data/refcounts.dat Sat Dec 20 08:39:56 2014 +0000
@@ -1753,7 +1753,7 @@
Py_FdIsInteractive:FILE*:fp::
Py_FdIsInteractive:const char*:filename::
-Py_Finalize:void:::
+Py_Finalize:int:::
Py_GetBuildInfoconst:const char*:::
diff -r 4e84e45e191b Doc/extending/embedding.rst
--- a/Doc/extending/embedding.rst Fri Dec 19 11:21:56 2014 -0500
+++ b/Doc/extending/embedding.rst Sat Dec 20 08:39:56 2014 +0000
@@ -67,7 +67,9 @@
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
- Py_Finalize();
+ if (Py_Finalize() < 0) {
+ exit(1);
+ }
PyMem_RawFree(program);
return 0;
}
diff -r 4e84e45e191b Doc/faq/extending.rst
--- a/Doc/faq/extending.rst Fri Dec 19 11:21:56 2014 -0500
+++ b/Doc/faq/extending.rst Sat Dec 20 08:39:56 2014 +0000
@@ -427,7 +427,10 @@
Py_XDECREF(glb);
Py_XDECREF(loc);
- Py_Finalize();
+ if (Py_Finalize() < 0)
+ {
+ exit(1);
+ }
exit(0);
}
diff -r 4e84e45e191b Doc/includes/run-func.c
--- a/Doc/includes/run-func.c Fri Dec 19 11:21:56 2014 -0500
+++ b/Doc/includes/run-func.c Sat Dec 20 08:39:56 2014 +0000
@@ -63,6 +63,8 @@
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
return 1;
}
- Py_Finalize();
+ if (Py_Finalize() < 0) {
+ return 1;
+ }
return 0;
}
diff -r 4e84e45e191b Include/pylifecycle.h
--- a/Include/pylifecycle.h Fri Dec 19 11:21:56 2014 -0500
+++ b/Include/pylifecycle.h Sat Dec 20 08:39:56 2014 +0000
@@ -26,7 +26,7 @@
#ifndef Py_LIMITED_API
PyAPI_FUNC(void) _Py_InitializeEx_Private(int, int);
#endif
-PyAPI_FUNC(void) Py_Finalize(void);
+PyAPI_FUNC(int) Py_Finalize(void);
PyAPI_FUNC(int) Py_IsInitialized(void);
PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void);
PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *);
diff -r 4e84e45e191b Lib/test/test_cmd_line.py
--- a/Lib/test/test_cmd_line.py Fri Dec 19 11:21:56 2014 -0500
+++ b/Lib/test/test_cmd_line.py Sat Dec 20 08:39:56 2014 +0000
@@ -342,8 +342,9 @@
import os, sys
sys.stdout.write('x')
os.close(sys.stdout.fileno())"""
- rc, out, err = assert_python_ok('-c', code)
+ rc, out, err = assert_python_failure('-c', code)
self.assertEqual(b'', out)
+ self.assertEqual(1, rc)
self.assertRegex(err.decode('ascii', 'ignore'),
'Exception ignored in.*\nOSError: .*')
diff -r 4e84e45e191b Modules/main.c
--- a/Modules/main.c Fri Dec 19 11:21:56 2014 -0500
+++ b/Modules/main.c Sat Dec 20 08:39:56 2014 +0000
@@ -784,7 +784,9 @@
sts = PyRun_AnyFileFlags(stdin, "", &cf) != 0;
}
- Py_Finalize();
+ if (Py_Finalize() < 0) {
+ sts = 1;
+ }
#ifdef __INSURE__
/* Insure++ is a memory analysis tool that aids in discovering
diff -r 4e84e45e191b PC/bdist_wininst/install.c
--- a/PC/bdist_wininst/install.c Fri Dec 19 11:21:56 2014 -0500
+++ b/PC/bdist_wininst/install.c Sat Dec 20 08:39:56 2014 +0000
@@ -329,7 +329,7 @@
{
DECLPROC(hPython, void, Py_Initialize, (void));
DECLPROC(hPython, void, Py_SetProgramName, (wchar_t *));
- DECLPROC(hPython, void, Py_Finalize, (void));
+ DECLPROC(hPython, int, Py_Finalize, (void));
DECLPROC(hPython, int, PyRun_SimpleString, (char *));
DECLPROC(hPython, PyObject *, PySys_GetObject, (char *));
DECLVAR(hPython, int, Py_OptimizeFlag);
@@ -709,7 +709,7 @@
* 1 if the Python-dll does not export the functions we need
* 2 if no install-script is specified in pathname
* 3 if the install-script file could not be opened
- * the return value of PyRun_SimpleString() otherwise,
+ * the return value of PyRun_SimpleString() or Py_Finalize() otherwise,
* which is 0 if everything is ok, -1 if an exception had occurred
* in the install-script.
*/
@@ -777,7 +777,9 @@
}
}
}
- Py_Finalize();
+ if (Py_Finalize() < 0) {
+ result = -1;
+ }
close(fh);
return result;
@@ -839,7 +841,7 @@
int rc;
DECLPROC(hPython, void, Py_Initialize, (void));
DECLPROC(hPython, void, Py_SetProgramName, (wchar_t *));
- DECLPROC(hPython, void, Py_Finalize, (void));
+ DECLPROC(hPython, int, Py_Finalize, (void));
DECLPROC(hPython, int, PyRun_SimpleString, (char *));
DECLPROC(hPython, void, PyErr_Print, (void));
@@ -853,7 +855,9 @@
rc = PyRun_SimpleString(script);
if (rc)
PyErr_Print();
- Py_Finalize();
+ if (Py_Finalize() < 0) {
+ rc = -1;
+ }
return rc;
}
@@ -1316,7 +1320,7 @@
{
void (__cdecl * Py_Initialize)(void);
void (__cdecl * Py_SetProgramName)(char *);
- void (__cdecl * Py_Finalize)(void);
+ int (__cdecl * Py_Finalize)(void);
void* (__cdecl * PySys_GetObject)(char *);
void (__cdecl * PySys_SetArgv)(int, char **);
char* (__cdecl * Py_GetPrefix)(void);
@@ -1358,7 +1362,7 @@
Py_GetPath = (char * (*)(void))GetProcAddress
(hPython,"Py_GetPath");
- Py_Finalize = (void (*)(void))GetProcAddress(hPython,
+ Py_Finalize = (int (*)(void))GetProcAddress(hPython,
"Py_Finalize");
Py_SetProgramName(exe);
Py_Initialize();
diff -r 4e84e45e191b Python/frozenmain.c
--- a/Python/frozenmain.c Fri Dec 19 11:21:56 2014 -0500
+++ b/Python/frozenmain.c Sat Dec 20 08:39:56 2014 +0000
@@ -96,7 +96,9 @@
#ifdef MS_WINDOWS
PyWinFreeze_ExeTerm();
#endif
- Py_Finalize();
+ if (Py_Finalize() < 0) {
+ sts = 1;
+ }
error:
PyMem_RawFree(argv_copy);
diff -r 4e84e45e191b Python/pylifecycle.c
--- a/Python/pylifecycle.c Fri Dec 19 11:21:56 2014 -0500
+++ b/Python/pylifecycle.c Sat Dec 20 08:39:56 2014 +0000
@@ -477,28 +477,34 @@
return r > 0;
}
-static void
+static int
flush_std_files(void)
{
PyObject *fout = _PySys_GetObjectId(&PyId_stdout);
PyObject *ferr = _PySys_GetObjectId(&PyId_stderr);
PyObject *tmp;
+ int status = 0;
if (fout != NULL && fout != Py_None && !file_is_closed(fout)) {
tmp = _PyObject_CallMethodId(fout, &PyId_flush, "");
- if (tmp == NULL)
+ if (tmp == NULL) {
PyErr_WriteUnraisable(fout);
- else
+ status = -1;
+ } else
Py_DECREF(tmp);
}
if (ferr != NULL && ferr != Py_None && !file_is_closed(ferr)) {
tmp = _PyObject_CallMethodId(ferr, &PyId_flush, "");
- if (tmp == NULL)
+ if (tmp == NULL) {
PyErr_Clear();
+ status = -1;
+ }
else
Py_DECREF(tmp);
}
+
+ return status;
}
/* Undo the effect of Py_Initialize().
@@ -515,14 +521,15 @@
*/
-void
+int
Py_Finalize(void)
{
PyInterpreterState *interp;
PyThreadState *tstate;
+ int status = 0;
if (!initialized)
- return;
+ return status;
wait_for_thread_shutdown();
@@ -547,7 +554,9 @@
initialized = 0;
/* Flush stdout+stderr */
- flush_std_files();
+ if (flush_std_files() < 0) {
+ status = -1;
+ }
/* Disable signal handling */
PyOS_FiniInterrupts();
@@ -576,7 +585,9 @@
PyImport_Cleanup();
/* Flush stdout+stderr (again, in case more was printed) */
- flush_std_files();
+ if (flush_std_files() < 0) {
+ status = -1;
+ }
/* Collect final garbage. This disposes of cycles created by
* class definitions, for example.
@@ -696,6 +707,7 @@
#endif
call_ll_exitfuncs();
+ return status;
}
/* Create and initialize a new interpreter and thread, and return the
@@ -993,7 +1005,8 @@
mode = "rb";
buf = _PyObject_CallMethodId(io, &PyId_open, "isiOOOi",
fd, mode, buffering,
- Py_None, Py_None, Py_None, 0);
+ Py_None, Py_None, /* encoding, errors */
+ Py_None, 0); /* newline, closefd */
if (buf == NULL)
goto error;
@@ -1367,7 +1380,9 @@
void
Py_Exit(int sts)
{
- Py_Finalize();
+ if (Py_Finalize() < 0) {
+ sts = 1;
+ }
exit(sts);
}