bug-gawk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Ignored SIGPIPE with line bufferization (wrapped by 'stdbuf -oL')


From: arnold
Subject: Re: Ignored SIGPIPE with line bufferization (wrapped by 'stdbuf -oL')
Date: Fri, 29 Jul 2022 01:55:56 -0600
User-agent: Heirloom mailx 12.5 7/5/10

Hi.

Thanks for the bug report.

Andy - thanks for the initial testing.  I agree that this looks like
a glibc bug. Fortunately, ferror() does give us some help, and I
have fixed the bug with the patch below. I will be pushing it to
git shortly.

Arnold

Nikita Zlobin <cook60020tmp@mail.ru> wrote:

> There's case, when it ignores SIGPIPE, but that happens only with line
> bufferization (using stdbuf). Disabled bufferization or manual flush
> (no stdbuf used) don't cause such problem.
>
> First reported for gentoo:
> https://bugs.gentoo.org/830705
>
> Besides releases this bug reproduces with git version
> (commit 74fcab9e4307e0d6a85c6e269eed3da276df08a4).
>
> 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
>
> head -n1 process usually disappears.
> stdbuf is from coreutils-8.32-r1.
-----------------------------
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;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]