NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

lib/60708: lib/: printf(3) leaves a positional %F argument untyped



>Number:         60708
>Category:       lib
>Synopsis:       printf(3) leaves a positional %F argument untyped, so "%1$F" prints the wrong value
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Sep 10 17:45:00 +0000 2026
>Originator:     Showta Ishizaki
>Release:        NetBSD 11.0 (the code is the same in -current)
>Organization:
>Environment:
System: NetBSD 11.0 amd64
Architecture: x86_64
Machine: amd64

>Description:

When a format uses positional arguments (n$), vfprintf(3) first walks
the format with __find_arguments() to learn the type of every argument,
and then reads them from a table.  That walk, in lib/libc/stdio/
vfwprintf.c, lists the floating-point conversions as

	case 'a':
	case 'A':
	case 'e':
	case 'E':
	case 'f':
	case 'g':
	case 'G':

and leaves out F.  A double that is only referred to through %F never
gets a type, so its slot in the table stays zero and the conversion
prints a zero:

	printf("%1$F", -INFINITY)   ->  0.000000
	printf("%1$F", 1.5)         ->  0.000000
	printf("%F", 1.5)           ->  1.500000

The same format with %1$f, or with %1$F next to any other conversion of
the same argument, works, because those give the argument its type.
The conversion switch itself already knows F (it sits next to 'f' at
line 1115), so only the type scan is missing it.

abseil's str_format test caught this on NetBSD: it prints "%1$*2$F" and
compares against the C library.

>How-To-Repeat:

	#include <stdio.h>
	#include <math.h>
	int main(void) {
		printf("[%1$F]\n", -INFINITY);
		printf("[%1$F]\n", 1.5);
		printf("[%F]\n", 1.5);
		return 0;
	}

prints

	[0.000000]
	[0.000000]
	[1.500000]

and the first two should be [-INF] and [1.500000].

>Fix:

Add 'F' to the list in __find_arguments().  The diff is against trunk
and applies to the netbsd-11 file as well.

--- lib/libc/stdio/vfwprintf.c.orig
+++ lib/libc/stdio/vfwprintf.c
@@ -1727,6 +1727,7 @@
 		case 'e':
 		case 'E':
 		case 'f':
+		case 'F':
 		case 'g':
 		case 'G':
 			if (flags & LONGDBL)

Checked by building lib/libc from the 11.0 source sets with this change
and running the program above against the new libc.so.12 through
LD_LIBRARY_PATH: it prints [-INF], [1.500000], [1.500000], and the
system libc still prints the zeros.  Not built on -current.

FreeBSD and DragonFly have the same omission in their printf-pos.c and
I am reporting it there separately; OpenBSD's vfprintf.c has the F.




Home | Main Index | Thread Index | Old Index