diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2022-07-29 11:05:25 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2022-07-29 11:05:25 +0300 |
commit | b71848d4f6ada1caade4289cc599561392f8be20 (patch) | |
tree | 72e817609972f6857f42b29fce035e52cea57651 | |
parent | c220a970623b597fc34064d0abf7776ecdcd302c (diff) | |
download | gawk-b71848d4f6ada1caade4289cc599561392f8be20.tar.gz |
Improve error checking on output.
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | awk.h | 1 | ||||
-rw-r--r-- | builtin.c | 20 | ||||
-rw-r--r-- | io.c | 2 |
4 files changed, 27 insertions, 3 deletions
@@ -1,3 +1,10 @@ +2022-07-29 Arnold D. Robbins <arnold@skeeve.com> + + * builtin.c (efwrite): Check ferror() also, fixes some weird + cases. Reported by Nikita Zlobin <cook60020tmp@mail.ru>. + * io.c (gawk_fwrite): Remove static from definition. + * awk.h (gawk_fwrite): Add declaration. + 2022-07-22 Arnold D. Robbins <arnold@skeeve.com> * NEWS: Updated. @@ -1665,6 +1665,7 @@ extern bool is_non_fatal_redirect(const char *str, size_t len); extern void ignore_sigpipe(void); extern void set_sigpipe_to_default(void); extern bool non_fatal_flush_std_file(FILE *fp); +extern size_t gawk_fwrite(const void *buf, size_t size, size_t count, FILE *fp, void *opaque); /* main.c */ extern int arg_assign(char *arg, bool initing); @@ -167,11 +167,27 @@ efwrite(const void *ptr, { errno = 0; if (rp != NULL) { - if (rp->output.gawk_fwrite(ptr, size, count, fp, rp->output.opaque) != count) { + /* + * 7/2022: We need to also check ferror(); there can be times when write(2) fails but + * fwrite succeeds! To do that, we make sure that rp->output.gawk_fwrite is not + * taken over by an extension before checking ferror(). From the bug report + * (https://lists.gnu.org/archive/html/bug-gawk/2022-07/msg00000.html): + * + * Minimal working example: + * yes | stdbuf -oL gawk '{print}' | head -n1 # Prints but hangs + * yes | stdbuf -o0 gawk '{print}' | head -n1 # OK + * yes | gawk '{print; fflush()}' | head -n1 # OK + * + * After this change, all three work. + */ + bool err_on_write = (rp->output.gawk_fwrite(ptr, size, count, fp, rp->output.opaque) != count); + bool err_on_fp = (rp->output.gawk_fwrite == gawk_fwrite && ferror(fp)); + + if (err_on_write || err_on_fp) { wrerror(fp, from, rp); return; } - } else if (fwrite(ptr, size, count, fp) != count) { + } else if (fwrite(ptr, size, count, fp) != count || ferror(fp)) { wrerror(fp, from, rp); return; } @@ -4413,7 +4413,7 @@ read_with_timeout(int fd, void *buf, size_t size) /* gawk_fwrite --- like fwrite */ -static size_t +size_t gawk_fwrite(const void *buf, size_t size, size_t count, FILE *fp, void *opaque) { (void) opaque; |