summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2022-07-29 11:05:25 +0300
committerArnold D. Robbins <arnold@skeeve.com>2022-07-29 11:05:25 +0300
commitb71848d4f6ada1caade4289cc599561392f8be20 (patch)
tree72e817609972f6857f42b29fce035e52cea57651
parentc220a970623b597fc34064d0abf7776ecdcd302c (diff)
downloadgawk-b71848d4f6ada1caade4289cc599561392f8be20.tar.gz
Improve error checking on output.
-rw-r--r--ChangeLog7
-rw-r--r--awk.h1
-rw-r--r--builtin.c20
-rw-r--r--io.c2
4 files changed, 27 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index cf5dd1aa..7da12705 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/awk.h b/awk.h
index dacf6f32..84fd714c 100644
--- a/awk.h
+++ b/awk.h
@@ -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);
diff --git a/builtin.c b/builtin.c
index 30795406..21125453 100644
--- a/builtin.c
+++ b/builtin.c
@@ -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;
}
diff --git a/io.c b/io.c
index 91fa2225..d7372b6f 100644
--- a/io.c
+++ b/io.c
@@ -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;