Skip to content

Commit 3092d6b

Browse files
authored
bpo-32849: Fix is_valid_fd() on FreeBSD (GH-12852)
Fix Python Initialization code on FreeBSD to detect properly when stdin file descriptor (fd 0) is invalid. On FreeBSD, fstat() must be used to check if stdin (fd 0) is valid. dup(0) doesn't fail if stdin is invalid in some cases.
1 parent 197f044 commit 3092d6b

File tree

2 files changed

+25
-15
lines changed

2 files changed

+25
-15
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix Python Initialization code on FreeBSD to detect properly when stdin file
2+
descriptor (fd 0) is invalid.

Python/pylifecycle.c

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,26 +1664,34 @@ initsite(void)
16641664
static int
16651665
is_valid_fd(int fd)
16661666
{
1667-
#ifdef __APPLE__
1668-
/* bpo-30225: On macOS Tiger, when stdout is redirected to a pipe
1669-
and the other side of the pipe is closed, dup(1) succeed, whereas
1670-
fstat(1, &st) fails with EBADF. Prefer fstat() over dup() to detect
1671-
such error. */
1672-
struct stat st;
1673-
return (fstat(fd, &st) == 0);
1674-
#else
1675-
int fd2;
1676-
if (fd < 0)
1667+
/* dup() is faster than fstat(): fstat() can require input/output operations,
1668+
whereas dup() doesn't. There is a low risk of EMFILE/ENFILE at Python
1669+
startup. Problem: dup() doesn't check if the file descriptor is valid on
1670+
some platforms.
1671+
1672+
bpo-30225: On macOS Tiger, when stdout is redirected to a pipe and the other
1673+
side of the pipe is closed, dup(1) succeed, whereas fstat(1, &st) fails with
1674+
EBADF. FreeBSD has similar issue (bpo-32849).
1675+
1676+
Only use dup() on platforms where dup() is enough to detect invalid FD in
1677+
corner cases: on Linux and Windows (bpo-32849). */
1678+
#if defined(__linux__) || defined(MS_WINDOWS)
1679+
if (fd < 0) {
16771680
return 0;
1681+
}
1682+
int fd2;
1683+
16781684
_Py_BEGIN_SUPPRESS_IPH
1679-
/* Prefer dup() over fstat(). fstat() can require input/output whereas
1680-
dup() doesn't, there is a low risk of EMFILE/ENFILE at Python
1681-
startup. */
16821685
fd2 = dup(fd);
1683-
if (fd2 >= 0)
1686+
if (fd2 >= 0) {
16841687
close(fd2);
1688+
}
16851689
_Py_END_SUPPRESS_IPH
1686-
return fd2 >= 0;
1690+
1691+
return (fd2 >= 0);
1692+
#else
1693+
struct stat st;
1694+
return (fstat(fd, &st) == 0);
16871695
#endif
16881696
}
16891697

0 commit comments

Comments
 (0)