diff options
author | Victor Stinner <vstinner@python.org> | 2024-04-30 20:32:55 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-30 20:32:55 (GMT) |
commit | e93c39b47ea623dfaf61f80775ad4747b163efe5 (patch) | |
tree | 0747773aa2298b73ff300c94dae89974dfc8f796 /Python/fileutils.c | |
parent | 587388ff22dc7cfa4b66722daf0d33cd804af9f2 (diff) | |
download | cpython-e93c39b47ea623dfaf61f80775ad4747b163efe5.zip cpython-e93c39b47ea623dfaf61f80775ad4747b163efe5.tar.gz cpython-e93c39b47ea623dfaf61f80775ad4747b163efe5.tar.bz2 |
gh-118422: Fix run_fileexflags() test (#118429)
Don't test the undefined behavior of fileno()
on a closed file, but use fstat() as a reliable
test if the file was closed or not.
Diffstat (limited to 'Python/fileutils.c')
-rw-r--r-- | Python/fileutils.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/Python/fileutils.c b/Python/fileutils.c index 54853ba..e6a5391 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -3050,3 +3050,52 @@ _Py_GetTicksPerSecond(long *ticks_per_second) return 0; } #endif + + +/* Check if a file descriptor is valid or not. + Return 0 if the file descriptor is invalid, return non-zero otherwise. */ +int +_Py_IsValidFD(int fd) +{ +/* dup() is faster than fstat(): fstat() can require input/output operations, + whereas dup() doesn't. There is a low risk of EMFILE/ENFILE at Python + startup. Problem: dup() doesn't check if the file descriptor is valid on + some platforms. + + fcntl(fd, F_GETFD) is even faster, because it only checks the process table. + It is preferred over dup() when available, since it cannot fail with the + "too many open files" error (EMFILE). + + bpo-30225: On macOS Tiger, when stdout is redirected to a pipe and the other + side of the pipe is closed, dup(1) succeed, whereas fstat(1, &st) fails with + EBADF. FreeBSD has similar issue (bpo-32849). + + Only use dup() on Linux where dup() is enough to detect invalid FD + (bpo-32849). +*/ + if (fd < 0) { + return 0; + } +#if defined(F_GETFD) && ( \ + defined(__linux__) || \ + defined(__APPLE__) || \ + (defined(__wasm__) && !defined(__wasi__))) + return fcntl(fd, F_GETFD) >= 0; +#elif defined(__linux__) + int fd2 = dup(fd); + if (fd2 >= 0) { + close(fd2); + } + return (fd2 >= 0); +#elif defined(MS_WINDOWS) + HANDLE hfile; + _Py_BEGIN_SUPPRESS_IPH + hfile = (HANDLE)_get_osfhandle(fd); + _Py_END_SUPPRESS_IPH + return (hfile != INVALID_HANDLE_VALUE + && GetFileType(hfile) != FILE_TYPE_UNKNOWN); +#else + struct stat st; + return (fstat(fd, &st) == 0); +#endif +} |