Fwd: [PATCH] coreutils/printf: fix errno clobbering with glibc 2.43
"Roberto A. Foglietta via busybox" <[email protected]>
| Newsgroups | gmane.linux.busybox |
|---|---|
| Message-ID | <CAJGKYO6sPCe106-gjoNK-byi_xvY5URjXmVnsE4T_QN21-KBcQ@mail.gmail.com> |
---------- Forwarded message --------- Because moderated by too many recipients On Mon, 30 Mar 2026 at 00:34, Roberto A. Foglietta <[email protected]> wrote: > > On Sun, 29 Mar 2026 at 23:38, David Laight <[email protected]> wrote: > > > > On Sun, 29 Mar 2026 23:10:37 +0200 > > "Roberto A. Foglietta" <[email protected]> wrote: > > > > [...] > > > > Relying only on a check of negative return value from printf() is a > > > too simple solution? Just asking, not humor. > > > > It doesn't work... > > Try: > > printf "fubar" >/dev/full > > > > Additionally even if printf() does return -1, errno is undefined. > > > > You need to call fflush() to get the buffered data written in order > > to get an error reported if the underlying write() system call fails. > > > > Which is why the correct solution is to ignore the return value from > > printf(). Instead call fflush(stdoout) and ferrror(stdout) before > > exiting. > > ...but flushing changes the behaviour of printf and impact on stderr > as well even when it is not involved. Unless the applet flush when > exit() because exit() would do anyway but doing first allows it to > catch the errors. ... but also exit() is not granted in an embedded > system that theoretically could run always as pid=1 and using alway > built-in applications without never exiting. (self-contained case). > Ignoring ENOENT everytime printf() size is not zero-length and avoid > it when it is zero length? The latter is a change in behavior (also) > but it can be seen as an optimization (step value to zero, not linear > optimization). > This should filter out the glibc dirty errno false positive (it is interesting that glibc asks busybox to fix a regression they create... lol). In fact, after having understood the issue, the best thing is that glibc clear errno when they know it is just a dirty value. https://github.com/robang74/busybox/tree/printf diff --git a/coreutils/printf.c b/coreutils/printf.c index f7d98debc..5ddcee167 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c @@ -240,9 +240,11 @@ static int print_direc(char *format, unsigned fmt_length, /* Hope compiler will optimize it out by moving call * instruction after the ifs... */ if (!have_width) { - if (!have_prec) + if (!have_prec) { + ret = 1; + if(argument[0]) ret = printf(format, argument, /*unused:*/ argument, argument); - else + } else ret = printf(format, precision, argument, /*unused:*/ argument); } else { if (!have_prec) @@ -377,15 +379,20 @@ static char **print_formatted(char *f, char **argv, int *conv_err) } else { p = NULL; } + #define ret precision if (*argv) { - *conv_err = + ret = print_direc(direc_start, direc_length, field_width, - precision, *argv++) < 0 ? 1 : 0; + precision, *argv++); } else { - *conv_err = + ret = print_direc(direc_start, direc_length, field_width, - precision, "") < 0 ? 1 : 0; + precision, ""); } + /* here ret cannot be zero unless a mistake happens + * because print_direc() is changed to skip "%s","" + */ + *conv_err |= (ret > 0) ? (errno && errno != ENOENT) : errno; free(p); } break; Best regards, R-