From f9c01a16dae8aa15d264a1937fb589e8598d1c88 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 16 Apr 2019 11:52:49 +0200 Subject: [PATCH] bpo-32849: Fix is_valid_fd() on FreeBSD 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. --- .../2019-04-16-11-56-12.bpo-32849.aeSg-D.rst | 2 + Python/pylifecycle.c | 38 +++++++++++-------- 2 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-04-16-11-56-12.bpo-32849.aeSg-D.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-04-16-11-56-12.bpo-32849.aeSg-D.rst b/Misc/NEWS.d/next/Core and Builtins/2019-04-16-11-56-12.bpo-32849.aeSg-D.rst new file mode 100644 index 00000000000000..6a9a85c4b13472 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-04-16-11-56-12.bpo-32849.aeSg-D.rst @@ -0,0 +1,2 @@ +Fix Python Initialization code on FreeBSD to detect properly when stdin file +descriptor (fd 0) is invalid. diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index ad1447256cc697..c7920ef6262d3c 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -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. */ - struct stat st; - return (fstat(fd, &st) == 0); -#else - int fd2; - if (fd < 0) +/* 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 - /* 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) + if (fd2 >= 0) { close(fd2); + } _Py_END_SUPPRESS_IPH - return fd2 >= 0; + + return (fd2 >= 0); +#else + struct stat st; + return (fstat(fd, &st) == 0); #endif }