summaryrefslogtreecommitdiff
path: root/lib/fclose.c
diff options
context:
space:
mode:
authorEric Blake <eblake@redhat.com>2011-05-10 15:28:48 -0600
committerEric Blake <eblake@redhat.com>2011-05-10 15:32:44 -0600
commit112b21e3861a4887731b61888d1388127957ba93 (patch)
treeb5af7b7828ae575e9fc15f9e7bb44cfa8b675962 /lib/fclose.c
parent38ed8cbdaac9ed0f1c8cbedfac78ca3f10991528 (diff)
downloadgnulib-112b21e3861a4887731b61888d1388127957ba93.tar.gz
fclose: avoid double close race when possible
Calling close(fileno(fp)) prior to fclose(fp) is racy in a multi-threaded application - some other thread could open a new file, which is then inadvertently closed by the fclose that we thought should fail with EBADF. For mingw, this is no worse than the race already present in close_fd_maybe_socket for calling closesocket() prior to _close(), but for all other platforms, we might as well be nice and avoid the race. * lib/fclose.c (rpl_fclose): Rewrite to avoid double-close race on all but WINDOWS_SOCKETS. Signed-off-by: Eric Blake <eblake@redhat.com>
Diffstat (limited to 'lib/fclose.c')
-rw-r--r--lib/fclose.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/lib/fclose.c b/lib/fclose.c
index bed561bdb1..018724b402 100644
--- a/lib/fclose.c
+++ b/lib/fclose.c
@@ -32,6 +32,7 @@ rpl_fclose (FILE *fp)
{
int saved_errno = 0;
int fd;
+ int result = 0;
/* Don't change behavior on memstreams. */
fd = fileno (fp);
@@ -45,15 +46,30 @@ rpl_fclose (FILE *fp)
&& fflush (fp))
saved_errno = errno;
+#if WINDOWS_SOCKETS
+ /* There is a minor race where some other thread could open fd
+ between our close and fopen, but it is no worse than the race in
+ close_fd_maybe_socket. */
if (close (fd) < 0 && saved_errno == 0)
saved_errno = errno;
- fclose (fp); /* will fail with errno = EBADF */
+ fclose (fp); /* will fail with errno = EBADF, if we did not lose a race */
if (saved_errno != 0)
{
errno = saved_errno;
- return EOF;
+ result = EOF;
}
- return 0;
+
+#else /* !WINDOWS_SOCKETS */
+ /* No race here. */
+ result = fclose (fp);
+
+# if REPLACE_FCHDIR
+ if (result == 0)
+ unregister_shadow_fd (fd);
+# endif
+#endif /* !WINDOWS_SOCKETS */
+
+ return result;
}