diff options
author | Rich Felker <dalias@aerifal.cx> | 2014-09-04 22:21:17 -0400 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2015-03-30 01:15:44 -0400 |
commit | f071365e66174937ffcb68c103e68573ce7dfd13 (patch) | |
tree | 25c8d41e51e721c69f51167af1a30930da7b5f63 | |
parent | 6d14779eabec925c3977584d5dfd52778047b856 (diff) | |
download | musl-f071365e66174937ffcb68c103e68573ce7dfd13.zip musl-f071365e66174937ffcb68c103e68573ce7dfd13.tar.gz musl-f071365e66174937ffcb68c103e68573ce7dfd13.tar.bz2 |
fix multiple stdio functions' behavior on zero-length operations
previously, fgets, fputs, fread, and fwrite completely omitted locking
and access to the FILE object when their arguments yielded a zero
length read or write operation independent of the FILE state. this
optimization was invalid; it wrongly skipped marking the stream as
byte-oriented (a C conformance bug) and exposed observably missing
synchronization (a POSIX conformance bug) where one of these functions
could wrongly complete despite another thread provably holding the
lock.
(cherry picked from commit 6e2bb7acf42589fb7130b039d0623e2ca42503dd)
-rw-r--r-- | src/stdio/fgets.c | 6 | ||||
-rw-r--r-- | src/stdio/fputs.c | 4 | ||||
-rw-r--r-- | src/stdio/fread.c | 5 | ||||
-rw-r--r-- | src/stdio/fwrite.c | 1 |
4 files changed, 7 insertions, 9 deletions
diff --git a/src/stdio/fgets.c b/src/stdio/fgets.c index cf5b103..d3f9819 100644 --- a/src/stdio/fgets.c +++ b/src/stdio/fgets.c @@ -10,14 +10,16 @@ char *fgets(char *restrict s, int n, FILE *restrict f) size_t k; int c; + FLOCK(f); + if (n--<=1) { + f->mode |= f->mode-1; + FUNLOCK(f); if (n) return 0; *s = 0; return s; } - FLOCK(f); - while (n) { z = memchr(f->rpos, '\n', f->rend - f->rpos); k = z ? z - f->rpos + 1 : f->rend - f->rpos; diff --git a/src/stdio/fputs.c b/src/stdio/fputs.c index 1112b19..4737f44 100644 --- a/src/stdio/fputs.c +++ b/src/stdio/fputs.c @@ -3,9 +3,7 @@ int fputs(const char *restrict s, FILE *restrict f) { - size_t l = strlen(s); - if (!l) return 0; - return (int)fwrite(s, l, 1, f) - 1; + return (int)fwrite(s, strlen(s), 1, f) - 1; } weak_alias(fputs, fputs_unlocked); diff --git a/src/stdio/fread.c b/src/stdio/fread.c index c461256..33a65f5 100644 --- a/src/stdio/fread.c +++ b/src/stdio/fread.c @@ -8,11 +8,10 @@ size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f) unsigned char *dest = destv; size_t len = size*nmemb, l = len, k; - /* Never touch the file if length is zero.. */ - if (!l) return 0; - FLOCK(f); + f->mode |= f->mode-1; + if (f->rend - f->rpos > 0) { /* First exhaust the buffer. */ k = MIN(f->rend - f->rpos, l); diff --git a/src/stdio/fwrite.c b/src/stdio/fwrite.c index d5f6542..81ec271 100644 --- a/src/stdio/fwrite.c +++ b/src/stdio/fwrite.c @@ -28,7 +28,6 @@ size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f) size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f) { size_t k, l = size*nmemb; - if (!l) return l; FLOCK(f); k = __fwritex(src, l, f); FUNLOCK(f); |