gh-127350: Add Py_fopen() and Py_fclose() functions (#127821)

This commit is contained in:
Victor Stinner 2025-01-06 13:43:09 +01:00 committed by GitHub
parent 7e8c571604
commit f89e5e20cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 270 additions and 53 deletions

View file

@ -1981,7 +1981,7 @@ _PyErr_ProgramDecodedTextObject(PyObject *filename, int lineno, const char* enco
return NULL;
}
FILE *fp = _Py_fopen_obj(filename, "r" PY_STDIOTEXTMODE);
FILE *fp = Py_fopen(filename, "r" PY_STDIOTEXTMODE);
if (fp == NULL) {
PyErr_Clear();
return NULL;

View file

@ -1748,8 +1748,10 @@ _Py_wfopen(const wchar_t *path, const wchar_t *mode)
}
/* Open a file. Call _wfopen() on Windows, or encode the path to the filesystem
encoding and call fopen() otherwise.
/* Open a file.
On Windows, if 'path' is a Unicode string, call _wfopen(). Otherwise, encode
the path to the filesystem encoding and call fopen().
Return the new file object on success. Raise an exception and return NULL
on error.
@ -1762,32 +1764,32 @@ _Py_wfopen(const wchar_t *path, const wchar_t *mode)
Release the GIL to call _wfopen() or fopen(). The caller must hold
the GIL. */
FILE*
_Py_fopen_obj(PyObject *path, const char *mode)
Py_fopen(PyObject *path, const char *mode)
{
FILE *f;
int async_err = 0;
#ifdef MS_WINDOWS
wchar_t wmode[10];
int usize;
assert(PyGILState_Check());
if (PySys_Audit("open", "Osi", path, mode, 0) < 0) {
return NULL;
}
if (!PyUnicode_Check(path)) {
PyErr_Format(PyExc_TypeError,
"str file path expected under Windows, got %R",
Py_TYPE(path));
FILE *f;
int async_err = 0;
int saved_errno;
#ifdef MS_WINDOWS
PyObject *unicode;
if (!PyUnicode_FSDecoder(path, &unicode)) {
return NULL;
}
wchar_t *wpath = PyUnicode_AsWideCharString(path, NULL);
if (wpath == NULL)
wchar_t *wpath = PyUnicode_AsWideCharString(unicode, NULL);
Py_DECREF(unicode);
if (wpath == NULL) {
return NULL;
}
usize = MultiByteToWideChar(CP_ACP, 0, mode, -1,
wmode, Py_ARRAY_LENGTH(wmode));
wchar_t wmode[10];
int usize = MultiByteToWideChar(CP_ACP, 0, mode, -1,
wmode, Py_ARRAY_LENGTH(wmode));
if (usize == 0) {
PyErr_SetFromWindowsErr(0);
PyMem_Free(wpath);
@ -1796,26 +1798,20 @@ _Py_fopen_obj(PyObject *path, const char *mode)
do {
Py_BEGIN_ALLOW_THREADS
_Py_BEGIN_SUPPRESS_IPH
f = _wfopen(wpath, wmode);
_Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS
} while (f == NULL
&& errno == EINTR && !(async_err = PyErr_CheckSignals()));
int saved_errno = errno;
saved_errno = errno;
PyMem_Free(wpath);
#else
PyObject *bytes;
const char *path_bytes;
assert(PyGILState_Check());
if (!PyUnicode_FSConverter(path, &bytes))
return NULL;
path_bytes = PyBytes_AS_STRING(bytes);
if (PySys_Audit("open", "Osi", path, mode, 0) < 0) {
Py_DECREF(bytes);
if (!PyUnicode_FSConverter(path, &bytes)) {
return NULL;
}
const char *path_bytes = PyBytes_AS_STRING(bytes);
do {
Py_BEGIN_ALLOW_THREADS
@ -1823,11 +1819,13 @@ _Py_fopen_obj(PyObject *path, const char *mode)
Py_END_ALLOW_THREADS
} while (f == NULL
&& errno == EINTR && !(async_err = PyErr_CheckSignals()));
int saved_errno = errno;
saved_errno = errno;
Py_DECREF(bytes);
#endif
if (async_err)
if (async_err) {
return NULL;
}
if (f == NULL) {
errno = saved_errno;
@ -1842,6 +1840,27 @@ _Py_fopen_obj(PyObject *path, const char *mode)
return f;
}
// Deprecated alias to Py_fopen() kept for backward compatibility
FILE*
_Py_fopen_obj(PyObject *path, const char *mode)
{
return Py_fopen(path, mode);
}
// Call fclose().
//
// On Windows, 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.

View file

@ -4688,7 +4688,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
* code relies on fp still being open. */
FILE *fp;
if (file != NULL) {
fp = _Py_fopen_obj(info.filename, "r");
fp = Py_fopen(info.filename, "r");
if (fp == NULL) {
goto finally;
}

View file

@ -467,7 +467,7 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit,
fclose(fp);
}
pyc_fp = _Py_fopen_obj(filename, "rb");
pyc_fp = Py_fopen(filename, "rb");
if (pyc_fp == NULL) {
fprintf(stderr, "python: Can't reopen .pyc file\n");
goto done;

View file

@ -2356,7 +2356,7 @@ static PyObject *
sys__dump_tracelets_impl(PyObject *module, PyObject *outpath)
/*[clinic end generated code: output=a7fe265e2bc3b674 input=5bff6880cd28ffd1]*/
{
FILE *out = _Py_fopen_obj(outpath, "wb");
FILE *out = Py_fopen(outpath, "wb");
if (out == NULL) {
return NULL;
}