# 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); }