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
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.