Download raw body.
nan(3): a long payload reaches the sign bit
_scan_nan() in lib/libm/src/s_nan.c fills every bit of the words it is
given, so a payload longer than the mantissa reaches the exponent and
the sign. nan() and nanf() OR in the exponent afterwards, which hides
that part, but the sign survives, and both nanl() variants assign the
exponent and leave the sign alone in the same way:
nan("9999999999999999") fff9999999999999
strtod("nan(9999999999999999)") 7ff9999999999999
nanf("ffffffff") ffffffff
strtof("nan(ffffffff)") 7fffffff
nanl("ffffffffffffffffffff") ffff ffffffffffffffff (sign set)
C11 7.12.11.2 defines nan(s) as strtod("NAN(s)"), so the two columns
should agree; the comment above _scan_nan() also says the high order
bits are discarded. abseil's charconv test compares from_chars, which
follows nan(3), against strtod and caught it.
The diff keeps only the mantissa in nan() and nanf() and clears the
sign in nanl(). I rebuilt lib/libm from the 7.9 source with it and
ran the probe against the new libm.so.10.1 through LD_LIBRARY_PATH:
nan("9999999999999999") is 7ff9999999999999, nanf("ffffffff") is
7fffffff, nanl("ffffffffffffffffffff") has 7fff in the sign and
exponent, and short payloads such as nan("1") are unchanged. Not built
on -current, though the diff applies to it unchanged.
Index: lib/libm/src/s_nan.c
--- lib/libm/src/s_nan.c.orig
+++ lib/libm/src/s_nan.c
@@ -101,10 +101,11 @@
} u;
_scan_nan(u.bits, 2, s);
+ /* Keep the mantissa only; a long payload must not reach the sign. */
#if BYTE_ORDER == LITTLE_ENDIAN
- u.bits[1] |= 0x7ff80000;
+ u.bits[1] = (u.bits[1] & 0x000fffff) | 0x7ff80000;
#else
- u.bits[0] |= 0x7ff80000;
+ u.bits[0] = (u.bits[0] & 0x000fffff) | 0x7ff80000;
#endif
return (u.d);
}
@@ -120,6 +121,6 @@
} u;
_scan_nan(u.bits, 1, s);
- u.bits[0] |= 0x7fc00000;
+ u.bits[0] = (u.bits[0] & 0x007fffff) | 0x7fc00000;
return (u.f);
}
Index: lib/libm/src/ld80/s_nanl.c
--- lib/libm/src/ld80/s_nanl.c.orig
+++ lib/libm/src/ld80/s_nanl.c
@@ -43,6 +43,7 @@
} u;
_scan_nan(u.bits, 3, s);
+ u.ieee.ext_sign = 0; /* a long payload must not reach the sign */
u.ieee.ext_exp = 0x7fff;
u.ieee.ext_frach |= 0xc0000000; /* make it a quiet NaN */
Index: lib/libm/src/ld128/s_nanl.c
--- lib/libm/src/ld128/s_nanl.c.orig
+++ lib/libm/src/ld128/s_nanl.c
@@ -43,6 +43,7 @@
} u;
_scan_nan(u.bits, 4, s);
+ u.ieee.ext_sign = 0; /* a long payload must not reach the sign */
u.ieee.ext_exp = 0x7fff;
u.ieee.ext_frach |= 1U << 15; /* make it a quiet NaN */
nan(3): a long payload reaches the sign bit