[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