summaryrefslogtreecommitdiff
path: root/manual/stdio.texi
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2017-05-05 11:31:38 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2017-05-22 18:13:35 -0300
commitf1a67a2c78601599be51a17250ca02c7d830d79d (patch)
treeac463077dcbc47e15e3b5346c445d9ddd38fcf0d /manual/stdio.texi
parentd26db8fbb4787905590f207d56026e915b3bd5b3 (diff)
libio: Avoid dup already opened file descriptor [BZ#21393]
As described in BZ#21398 (close as dup of 21393) report current freopen implementation fails when one tries to freopen STDIN_FILENO, STDOUT_FILENO, or STDERR_FILENO. Although on bug report the discussion leads to argue if a close followed by a freopen on the standard file is a valid operation, the underlying issue is not really the check for dup3 returned value, but rather calling it if the returned file descriptor is equal as the input one. So for a quality of implementation this patch avoid calling dup3 for the aforementioned case. It also adds a dup3 error case check for the two possible failures, with one being Linux only: EINTR and EBUSY. The EBUSY issue is better explained on this stackoverflow thread [1], but in a short it is due the internal Linux implementation which allows a race condition window for dup2 due the logic dissociation of file descriptor allocation and actual VFS 'install' operation. For both outliers failures all allocated memory is freed and a NULL FILE* is returned. With this patch the example on BZ#21398 is now actually possible (I used as the testcase for the bug report). Checked on x86_64-linux-gnu. [BZ #21393] * libio/freopen.c (freopen): Avoid dup already opened file descriptor and add a check for dup3 failure. * libio/freopen64.c (freopen64): Likewise. * libio/tst-freopen.c (do_test): Rename to do_test_basic and use libsupport. (do_test_bz21398): New test. * manual/stdio.texi (freopen): Add documentation of EBUSY failure. [1] http://stackoverflow.com/questions/23440216/race-condition-when-using-dup2
Diffstat (limited to 'manual/stdio.texi')
-rw-r--r--manual/stdio.texi10
1 files changed, 9 insertions, 1 deletions
diff --git a/manual/stdio.texi b/manual/stdio.texi
index dbb21ca4a9..29f3fed89b 100644
--- a/manual/stdio.texi
+++ b/manual/stdio.texi
@@ -316,7 +316,15 @@ actually done any output using the stream.) Then the file named by
and associated with the same stream object @var{stream}.
If the operation fails, a null pointer is returned; otherwise,
-@code{freopen} returns @var{stream}.
+@code{freopen} returns @var{stream}. On Linux, @code{freopen} may also
+fail and set @code{errno} to @code{EBUSY} when the kernel structure for
+the old file descriptor was not initialized completely before @code{freopen}
+was called. This can only happen in multi-threaded programs, when two
+threads race to allocate the same file descriptor number. To avoid the
+possibility of this race, do not use @code{close} to close the underlying
+file descriptor for a @code{FILE}; either use @code{freopen} while the
+file is still open, or use @code{open} and then @code{dup2} to install
+the new file descriptor.
@code{freopen} has traditionally been used to connect a standard stream
such as @code{stdin} with a file of your own choice. This is useful in