[PATCH RESEND 01/14] stdio-common: Add tests for formatted scanf input specifiers

Joseph Myers josmyers@redhat.com
Sat Feb 15 01:23:41 GMT 2025


On Mon, 10 Feb 2025, Maciej W. Rozycki wrote:

> +/* Reference data is a case-inensitive signed datum, which is either a
> +   hexadecimal floating constant or a literal representing infinity or
> +   NaN data in any of the forms accepted by 'strtod' family functions,
> +   whose binary representation is to match against byte-wise.
> +
> +   We need to be careful with parsing reference data in the handling of
> +   the sign as with the IBM long double binary format unary negation
> +   of a positive value whose lower-magnitude part is zero produces a
> +   bit pattern that is different from one produced by initialization or
> +   conversions made by functions such as 'scanf' or 'strtod' from the
> +   complementing negative value.  The difference is in the sign of zero
> +   held in the lower-magnitude part and therefore the bit patterns are
> +   arithmetically equivalent, but they do not match byte-wise.
> +
> +   Therefore we set the sign with the initial value of the significand,
> +   either -0.0 or 0.0, which sets the sign of both parts according to
> +   what 'scanf' does, and never negate it afterwards.
> +
> +   Additionally the Intel long double binary format uses only 80 bits
> +   out of 96 that the data type occupies.  Therefore preinitialize the
> +   reference value with the same 0xa5 bit pattern that the value under
> +   test has been so that the byte-wise comparison matches as well for
> +   the unused parts of the two data pieces.

I don't think it's safe to make any assumptions about whether padding bits 
of x86 (or m68k?) long double are or are not modified by scanf; that may 
depend on the details of what instructions the compiler happens to 
generate in scanf to store the long double value that's been read.  So I 
don't think the strategy of comparing with memcmp is safe in that case, 
unless you first copy just the value bits (and not padding bits) to a 
character array (or other type without room for the padding bits) before 
comparing.

For IBM long double, the cases where the bit pattern is not fully defined 
are (a) the low 64 bits of a NaN are entirely unspecified; (b) if the low 
part is zero, its sign does not matter (regardless of the value of the 
high part).  You're less likely to have things varying with the details of 
compiler code generation there, however.

For NaNs in general, if a payload is *not* specified in the scanf string 
then you'll get whatever default NaN scanf returns, while computing some 
default NaN in the test code.  Maybe these are in fact reliably the same, 
but it's beyond the API I'd consider to be guaranteed.

In short: for x86/m68k long double I think the comparison approach used is 
unreliable, depending on the compiler version, because it relies on 
padding bits not changing.  For IBM long double and for NaNs without 
payload specified, I think comparing using memcmp means you're at least 
testing internal implementation details (whether intentionally or 
otherwise) that go beyond what I think is properly part of the specified 
API for glibc.

-- 
Joseph S. Myers
josmyers@redhat.com



More information about the Libc-alpha mailing list