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-
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.