From f071365e66174937ffcb68c103e68573ce7dfd13 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 4 Sep 2014 22:21:17 -0400 Subject: 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) --- src/stdio/fgets.c | 6 ++++-- src/stdio/fputs.c | 4 +--- src/stdio/fread.c | 5 ++--- 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 cf5b1039..d3f9819e 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 1112b192..4737f448 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 c461256c..33a65f58 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 d5f6542d..81ec271e 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); -- cgit v1.2.1