diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index d51e66d45d22b3..21f5c813c5dcdd 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -226,6 +226,9 @@ Operating System Utilities On success, return the new file object. On error, set an exception and return ``NULL``. + The file must be closed by :c:func:`Py_fclose` rather than calling directly + ``fclose()``. + The file descriptor is created non-inheritable (:pep:`446`). The caller must hold the GIL. @@ -233,6 +236,18 @@ Operating System Utilities .. versionadded:: next +.. c:function:: int Py_fclose(FILE *file) + + Call ``fclose(file)``. + + This function is needed on Windows: ``FILE*`` files opened by + :c:func:`Py_fopen` in the Python DLL must be closed by the Python DLL to use + the same C runtime version. Otherwise, calling ``fclose()`` directly can + cause undefined behavior. + + .. versionadded:: next + + .. _systemfunctions: System Functions diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 2ce1bcdad75fbc..22221cc51675ec 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1036,7 +1036,8 @@ New features * Add :c:func:`Py_fopen` function to open a file. Similar to the :c:func:`!fopen` function, but the *path* parameter is a Python object and an - exception is set on error. + exception is set on error. Add also :c:func:`Py_fclose` function to close a + file, function needed for Windows support. (Contributed by Victor Stinner in :gh:`127350`.) Porting to Python 3.14 diff --git a/Include/cpython/fileutils.h b/Include/cpython/fileutils.h index 3a2bfae1add88e..c65e5d807266d6 100644 --- a/Include/cpython/fileutils.h +++ b/Include/cpython/fileutils.h @@ -5,3 +5,5 @@ PyAPI_FUNC(FILE*) Py_fopen( PyObject *path, const char *mode); + +PyAPI_FUNC(int) Py_fclose(FILE *file); diff --git a/Misc/NEWS.d/next/C_API/2024-12-11-13-01-26.gh-issue-127350.uEBZZ4.rst b/Misc/NEWS.d/next/C_API/2024-12-11-13-01-26.gh-issue-127350.uEBZZ4.rst index e3a914188ca680..d1b528c673442f 100644 --- a/Misc/NEWS.d/next/C_API/2024-12-11-13-01-26.gh-issue-127350.uEBZZ4.rst +++ b/Misc/NEWS.d/next/C_API/2024-12-11-13-01-26.gh-issue-127350.uEBZZ4.rst @@ -1,3 +1,5 @@ Add :c:func:`Py_fopen` function to open a file. Similar to the :c:func:`!fopen` function, but the *path* parameter is a Python object and an exception is set -on error. Patch by Victor Stinner. +on error. Add also :c:func:`Py_fclose` function to close a file, function +needed for Windows support. +Patch by Victor Stinner. diff --git a/Modules/_testcapi/file.c b/Modules/_testcapi/file.c index b163ec0efcb78b..0ce0780623b9cd 100644 --- a/Modules/_testcapi/file.c +++ b/Modules/_testcapi/file.c @@ -17,7 +17,7 @@ _testcapi.py_fopen mode: str / -Call Py_fopen() and return fread(256). +Call Py_fopen(), fread(256) and Py_fclose(). Return read bytes. [clinic start generated code]*/ static PyObject * @@ -31,7 +31,7 @@ _testcapi_py_fopen_impl(PyObject *module, PyObject *path, const char *mode) char buffer[256]; size_t size = fread(buffer, 1, Py_ARRAY_LENGTH(buffer), fp); - fclose(fp); + Py_fclose(fp); return PyBytes_FromStringAndSize(buffer, size); } diff --git a/Python/fileutils.c b/Python/fileutils.c index c039fdc8f3309e..7075e6a6938efe 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -1836,6 +1836,19 @@ Py_fopen(PyObject *path, const char *mode) return f; } + +// Call fclose(). +// +// This function is needed on Windows: FILE* files opened by Py_fopen() in the +// Python DLL must be closed by the Python DLL to use the same C runtime +// version. Otherwise, calling fclose() directly can cause undefined behavior. +int +Py_fclose(FILE *file) +{ + return fclose(file); +} + + /* Read count bytes from fd into buf. On success, return the number of read bytes, it can be lower than count.