diff options
author | Eric Blake <eblake@redhat.com> | 2011-05-10 15:28:48 -0600 |
---|---|---|
committer | Eric Blake <eblake@redhat.com> | 2011-05-10 15:32:44 -0600 |
commit | 112b21e3861a4887731b61888d1388127957ba93 (patch) | |
tree | b5af7b7828ae575e9fc15f9e7bb44cfa8b675962 /lib/fclose.c | |
parent | 38ed8cbdaac9ed0f1c8cbedfac78ca3f10991528 (diff) | |
download | gnulib-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.c | 22 |
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; } |