summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2025-01-06 12:43:09 (GMT)
committerGitHub <noreply@github.com>2025-01-06 12:43:09 (GMT)
commitf89e5e20cb8964653ea7d6f53d3e40953b6548ce (patch)
tree743bfa078c6861561f1a1b908fc848b968e89fad /Python
parent7e8c571604cd18e65cefd26bfc48082840264549 (diff)
downloadcpython-f89e5e20cb8964653ea7d6f53d3e40953b6548ce.zip
cpython-f89e5e20cb8964653ea7d6f53d3e40953b6548ce.tar.gz
cpython-f89e5e20cb8964653ea7d6f53d3e40953b6548ce.tar.bz2
gh-127350: Add Py_fopen() and Py_fclose() functions (#127821)
Diffstat (limited to 'Python')
-rw-r--r--Python/errors.c2
-rw-r--r--Python/fileutils.c79
-rw-r--r--Python/import.c2
-rw-r--r--Python/pythonrun.c2
-rw-r--r--Python/sysmodule.c2
5 files changed, 53 insertions, 34 deletions
diff --git a/Python/errors.c b/Python/errors.c
index 2d362c1..b6ac2f7 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -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;
diff --git a/Python/fileutils.c b/Python/fileutils.c
index 8127665..6bc3a44 100644
--- a/Python/fileutils.c
+++ b/Python/fileutils.c
@@ -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.
diff --git a/Python/import.c b/Python/import.c
index a9282dd..b3648e2 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -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;
}
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 31e065f..0da26ad 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -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;
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index d6719f9..887591a 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -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;
}