diff options
-rw-r--r-- | src/stdio/fclose.c | 7 | ||||
-rw-r--r-- | src/stdio/feof.c | 5 | ||||
-rw-r--r-- | src/stdio/ferror.c | 5 | ||||
-rw-r--r-- | src/stdio/fileno.c | 5 | ||||
-rw-r--r-- | src/stdio/freopen.c | 24 | ||||
-rw-r--r-- | src/stdio/fwide.c | 6 |
6 files changed, 36 insertions, 16 deletions
diff --git a/src/stdio/fclose.c b/src/stdio/fclose.c index 8fdc3f7d..92bf7ff8 100644 --- a/src/stdio/fclose.c +++ b/src/stdio/fclose.c @@ -3,9 +3,12 @@ int fclose(FILE *f) { int r; - int perm = f->flags & F_PERM; + int perm; + + /* This lock is not paired with any unlock. */ + FLOCK(f); - if (!perm) { + if (!(perm = f->flags & F_PERM)) { OFLLOCK(); if (f->prev) f->prev->next = f->next; if (f->next) f->next->prev = f->prev; diff --git a/src/stdio/feof.c b/src/stdio/feof.c index 5d7f4b02..56da6b91 100644 --- a/src/stdio/feof.c +++ b/src/stdio/feof.c @@ -4,7 +4,10 @@ int feof(FILE *f) { - return !!(f->flags & F_EOF); + FLOCK(f); + int ret = !!(f->flags & F_EOF); + FUNLOCK(f); + return ret; } weak_alias(feof, feof_unlocked); diff --git a/src/stdio/ferror.c b/src/stdio/ferror.c index 8288a93d..d692eed9 100644 --- a/src/stdio/ferror.c +++ b/src/stdio/ferror.c @@ -4,7 +4,10 @@ int ferror(FILE *f) { - return !!(f->flags & F_ERR); + FLOCK(f); + int ret = !!(f->flags & F_ERR); + FUNLOCK(f); + return ret; } weak_alias(ferror, ferror_unlocked); diff --git a/src/stdio/fileno.c b/src/stdio/fileno.c index 9ffb26d5..ba7f9391 100644 --- a/src/stdio/fileno.c +++ b/src/stdio/fileno.c @@ -2,6 +2,11 @@ int fileno(FILE *f) { + /* f->fd never changes, but the lock must be obtained and released + * anyway since this function cannot return while another thread + * holds the lock. */ + FLOCK(f); + FUNLOCK(f); return f->fd; } diff --git a/src/stdio/freopen.c b/src/stdio/freopen.c index c80ce3b4..7ae116d8 100644 --- a/src/stdio/freopen.c +++ b/src/stdio/freopen.c @@ -4,8 +4,9 @@ * hack the necessary parts of the new FILE into the old one, then * close the new FILE. */ -/* Locking is not necessary because, in the event of failure, the stream - * passed to freopen is invalid as soon as freopen is called. */ +/* Locking IS necessary because another thread may provably hold the + * lock, via flockfile or otherwise, when freopen is called, and in that + * case, freopen cannot act until the lock is released. */ int __dup3(int, int, int); @@ -14,6 +15,8 @@ FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *re int fl = __fmodeflags(mode); FILE *f2; + FLOCK(f); + fflush(f); if (!filename) { @@ -22,21 +25,22 @@ FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *re fl &= ~(O_CREAT|O_EXCL|O_CLOEXEC); if (syscall(SYS_fcntl, f->fd, F_SETFL, fl) < 0) goto fail; - return f; } else { f2 = fopen(filename, mode); if (!f2) goto fail; if (f2->fd == f->fd) f2->fd = -1; /* avoid closing in fclose */ else if (__dup3(f2->fd, f->fd, fl&O_CLOEXEC)<0) goto fail2; - } - f->flags = (f->flags & F_PERM) | f2->flags; - f->read = f2->read; - f->write = f2->write; - f->seek = f2->seek; - f->close = f2->close; + f->flags = (f->flags & F_PERM) | f2->flags; + f->read = f2->read; + f->write = f2->write; + f->seek = f2->seek; + f->close = f2->close; - fclose(f2); + fclose(f2); + } + + FUNLOCK(f); return f; fail2: diff --git a/src/stdio/fwide.c b/src/stdio/fwide.c index f4da47f6..48480685 100644 --- a/src/stdio/fwide.c +++ b/src/stdio/fwide.c @@ -5,6 +5,8 @@ int fwide(FILE *f, int mode) { - if (!f->mode) f->mode = NORMALIZE(mode); - return f->mode; + FLOCK(f); + if (!f->mode) mode = f->mode = NORMALIZE(mode); + FUNLOCK(f); + return mode; } |