[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;