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.
This commit is contained in:
Victor Stinner 2019-04-17 18:09:12 +02:00 committed by GitHub
parent 197f0447e3
commit 3092d6b263
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 18 deletions

View File

@ -0,0 +1,2 @@
Fix Python Initialization code on FreeBSD to detect properly when stdin file
descriptor (fd 0) is invalid.

View File

@ -1664,26 +1664,34 @@ initsite(void)
static int
is_valid_fd(int fd)
{
#ifdef __APPLE__
/* 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. Prefer fstat() over dup() to detect
such error. */
/* 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.
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 platforms where dup() is enough to detect invalid FD in
corner cases: on Linux and Windows (bpo-32849). */
#if defined(__linux__) || defined(MS_WINDOWS)
if (fd < 0) {
return 0;
}
int fd2;
_Py_BEGIN_SUPPRESS_IPH
fd2 = dup(fd);
if (fd2 >= 0) {
close(fd2);
}
_Py_END_SUPPRESS_IPH
return (fd2 >= 0);
#else
struct stat st;
return (fstat(fd, &st) == 0);
#else
int fd2;
if (fd < 0)
return 0;
_Py_BEGIN_SUPPRESS_IPH
/* Prefer dup() over fstat(). fstat() can require input/output whereas
dup() doesn't, there is a low risk of EMFILE/ENFILE at Python
startup. */
fd2 = dup(fd);
if (fd2 >= 0)
close(fd2);
_Py_END_SUPPRESS_IPH
return fd2 >= 0;
#endif
}