Re: [PATCH] coreutils/printf: fix errno clobbering with glibc 2.43
David Laight via busybox <[email protected]>
| Newsgroups | gmane.linux.busybox |
|---|---|
| Message-ID | <20260317141607.2dd53a61@pumpkin> |
On Tue, 17 Mar 2026 11:30:06 +0100 Rasmus Villemoes <[email protected]> wrote: > On Tue, Mar 17 2026, Harald van Dijk via busybox <[email protected]> wrote: > > > On 16/03/2026 14:23, David Laight via busybox wrote: > >> On Mon, 16 Mar 2026 12:40:59 +0530 > >> Hemanth Kumar M D via busybox <[email protected]> wrote: > >> > >>> busybox printf uses errno as an accumulator and returns exit code 1 > >>> if errno is non-zero. > > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > This is the bug in busybox that should be fixed. > > > Since glibc > >>> 2.43 unexpectedly sets errno during successful printf() calls, busybox > >>> printf returns exit code 1 even when output is correct: > >>> > >>> FAIL: printf understands %s '"x' "'y" "'zTAIL" (exit 1, expected 0) > >>> FAIL: printf handles positive numbers for %f (exit 1, expected 0) > >>> > >>> Note: the printf output itself is correct in both cases — only the > >>> exit code is wrong. > >>> > >>> Fix by saving and restoring errno around each printf() call in > >>> coreutils/printf.c, only preserving a non-zero errno if an actual > >>> error occurred (ret < 0). > >> That seems like the wrong fix for the problem - but your patch is > >> mangled. > > > > It looks like the right fix to me. > > No. Almost every single libc function is allowed to set errno > "spuriously", one simply cannot rely on errno being 0 as an indicator > for a succesful call. There are a few, documented, exceptions, such as > the strtol family where any return value is possible, so one has to set > errno to 0 before and then (for certain return values) check it > afterwards. > > But very few libc functions are guaranteed not to touch errno when they > succeed. > > The value of errno in the initial thread shall be zero at program > startup (the initial value of errno in other threads is an > indeterminate value) and shall otherwise be defined only after a call > to a function for which it is explicitly stated to be set and until it > is changed by the next function call or if the application assigns it > a value. The value of errno should only be examined when it is > indicated to be valid by a function's return value. > > No function in this volume of POSIX.1-2024 shall set errno to 0. The > setting of errno after a successful call to a function is unspecified > unless the description of that function specifies that errno shall not > be modified. I had a feeling that was true - but couldn't be 100% certain. > And yes, as David also points out, fprintf() itself is unlikely to return > an error, at least for the I/O part - of course it may return an error > if the format string is somehow invalid. I don't believe there any such error conditions. But consider what printf("%*s %*s", MAXINT, "", MAXINT, "") returns. That won't even take a really silly time to execute either. > But it seems that ferror() is > exactly what busybox wants (after calling fflush() at the end). Clearly you can add: if (ferror(stdout)) exit(1); in the loop to exit early - but for printf that is probably not needed. You might find that 'printf foo >/dev/full' will test the error handling. libc is likely to set 'block buffering' so the write won't happen until the final fclose(). David > > Rasmus _______________________________________________ busybox mailing list [email protected] https://lists.busybox.net/mailman/listinfo/busybox