Fix sscanf/wcstod parsing of NaNs.

The parsefloat routines -- which let us pass NaNs and infinities on to
strto(f|d|ld) -- come from NetBSD.

Also fix LP64's strtold to return a NaN, and fix all the architectures
to return quiet NaNs.

Also fix wcstof/wcstod/wcstold to use parsefloat so they support hex
floats.

Lots of new tests.

Bug: http://b/31101647
Change-Id: Id7d46ac2d8acb8770b5e8c445e87cfabfde6f111
diff --git a/tests/math_data_test.h b/tests/math_data_test.h
index 0aba701..42dc42c 100644
--- a/tests/math_data_test.h
+++ b/tests/math_data_test.h
@@ -16,6 +16,7 @@
 
 #include <gtest/gtest.h>
 
+#include <math.h>
 #include <fenv.h>
 
 template <typename RT, typename T1>
@@ -102,7 +103,28 @@
   uint64_t sign_magnitude;
 };
 
-// TODO: long double.
+template <> union fp_u<long double> {
+  long double value;
+#if defined(__LP64__)
+  struct {
+    unsigned fracl;
+    unsigned fraclm;
+    unsigned frachm;
+    unsigned frach:16;
+    unsigned exp:15;
+    unsigned sign:1;
+  } bits;
+  __int128_t sign_magnitude;
+#else
+  struct {
+      unsigned fracl;
+      unsigned frach:20;
+      unsigned exp:11;
+      unsigned sign:1;
+  } bits;
+  uint64_t sign_magnitude;
+#endif
+};
 
 template <typename T>
 static inline auto SignAndMagnitudeToBiased(const T& value) -> decltype(fp_u<T>::sign_magnitude) {
@@ -134,14 +156,8 @@
       return ::testing::AssertionSuccess();
     }
 
-    // Output the actual and expected values as hex floating point.
-    char expected_str[64];
-    char actual_str[64];
-    snprintf(expected_str, sizeof(expected_str), "%a", expected);
-    snprintf(actual_str, sizeof(actual_str), "%a", actual);
-
     return ::testing::AssertionFailure()
-        << "expected (" << expected_str << ") != actual (" << actual_str << ")";
+        << "expected (" << std::hexfloat << expected << ") != actual (" << actual << ")";
   }
 };
 
@@ -282,4 +298,3 @@
                         data[i].expected, f(data[i].input1, data[i].input2, data[i].input3)) << "Failed on element " << i;
   }
 }
-
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index ecba4ad..79c5e92 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -402,51 +402,135 @@
 }
 
 template <typename T>
-void CheckInfNan(int snprintf_fn(T*, size_t, const T*, ...),
-                 const T* fmt, const T* fmt_plus,
-                 const T* minus_inf, const T* inf_, const T* plus_inf,
-                 const T* minus_nan, const T* nan_, const T* plus_nan) {
+static void CheckInfNan(int snprintf_fn(T*, size_t, const T*, ...),
+                        int sscanf_fn(const T*, const T*, ...),
+                        const T* fmt_string, const T* fmt, const T* fmt_plus,
+                        const T* minus_inf, const T* inf_, const T* plus_inf,
+                        const T* minus_nan, const T* nan_, const T* plus_nan) {
   T buf[BUFSIZ];
+  float f;
 
-  snprintf_fn(buf, sizeof(buf), fmt, nan(""));
+  // NaN.
+
+  snprintf_fn(buf, sizeof(buf), fmt, nanf(""));
   EXPECT_STREQ(nan_, buf) << fmt;
-  snprintf_fn(buf, sizeof(buf), fmt, -nan(""));
+  EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+  EXPECT_TRUE(isnan(f));
+
+  snprintf_fn(buf, sizeof(buf), fmt, -nanf(""));
   EXPECT_STREQ(minus_nan, buf) << fmt;
-  snprintf_fn(buf, sizeof(buf), fmt_plus, nan(""));
+  EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+  EXPECT_TRUE(isnan(f));
+
+  snprintf_fn(buf, sizeof(buf), fmt_plus, nanf(""));
   EXPECT_STREQ(plus_nan, buf) << fmt_plus;
-  snprintf_fn(buf, sizeof(buf), fmt_plus, -nan(""));
+  EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+  EXPECT_TRUE(isnan(f));
+
+  snprintf_fn(buf, sizeof(buf), fmt_plus, -nanf(""));
   EXPECT_STREQ(minus_nan, buf) << fmt_plus;
+  EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+  EXPECT_TRUE(isnan(f));
 
-  snprintf_fn(buf, sizeof(buf), fmt, HUGE_VAL);
+  // Inf.
+
+  snprintf_fn(buf, sizeof(buf), fmt, HUGE_VALF);
   EXPECT_STREQ(inf_, buf) << fmt;
-  snprintf_fn(buf, sizeof(buf), fmt, -HUGE_VAL);
+  EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+  EXPECT_EQ(HUGE_VALF, f);
+
+  snprintf_fn(buf, sizeof(buf), fmt, -HUGE_VALF);
   EXPECT_STREQ(minus_inf, buf) << fmt;
-  snprintf_fn(buf, sizeof(buf), fmt_plus, HUGE_VAL);
+  EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+  EXPECT_EQ(-HUGE_VALF, f);
+
+  snprintf_fn(buf, sizeof(buf), fmt_plus, HUGE_VALF);
   EXPECT_STREQ(plus_inf, buf) << fmt_plus;
-  snprintf_fn(buf, sizeof(buf), fmt_plus, -HUGE_VAL);
+  EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+  EXPECT_EQ(HUGE_VALF, f);
+
+  snprintf_fn(buf, sizeof(buf), fmt_plus, -HUGE_VALF);
   EXPECT_STREQ(minus_inf, buf) << fmt_plus;
+  EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+  EXPECT_EQ(-HUGE_VALF, f);
+
+  // Check case-insensitivity.
+  snprintf_fn(buf, sizeof(buf), fmt_string, "[InFiNiTy]");
+  EXPECT_EQ(1, sscanf_fn(buf, fmt, &f)) << buf;
+  EXPECT_EQ(HUGE_VALF, f);
+  snprintf_fn(buf, sizeof(buf), fmt_string, "[NaN]");
+  EXPECT_EQ(1, sscanf_fn(buf, fmt, &f)) << buf;
+  EXPECT_TRUE(isnan(f));
 }
 
-TEST(STDIO_TEST, snprintf_inf_nan) {
-  CheckInfNan(snprintf, "%a", "%+a", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
-  CheckInfNan(snprintf, "%A", "%+A", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
-  CheckInfNan(snprintf, "%e", "%+e", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
-  CheckInfNan(snprintf, "%E", "%+E", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
-  CheckInfNan(snprintf, "%f", "%+f", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
-  CheckInfNan(snprintf, "%F", "%+F", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
-  CheckInfNan(snprintf, "%g", "%+g", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
-  CheckInfNan(snprintf, "%G", "%+G", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
+TEST(STDIO_TEST, snprintf_sscanf_inf_nan) {
+  CheckInfNan(snprintf, sscanf, "%s",
+              "[%a]", "[%+a]",
+              "[-inf]", "[inf]", "[+inf]",
+              "[-nan]", "[nan]", "[+nan]");
+  CheckInfNan(snprintf, sscanf, "%s",
+              "[%A]", "[%+A]",
+              "[-INF]", "[INF]", "[+INF]",
+              "[-NAN]", "[NAN]", "[+NAN]");
+  CheckInfNan(snprintf, sscanf, "%s",
+              "[%e]", "[%+e]",
+              "[-inf]", "[inf]", "[+inf]",
+              "[-nan]", "[nan]", "[+nan]");
+  CheckInfNan(snprintf, sscanf, "%s",
+              "[%E]", "[%+E]",
+              "[-INF]", "[INF]", "[+INF]",
+              "[-NAN]", "[NAN]", "[+NAN]");
+  CheckInfNan(snprintf, sscanf, "%s",
+              "[%f]", "[%+f]",
+              "[-inf]", "[inf]", "[+inf]",
+              "[-nan]", "[nan]", "[+nan]");
+  CheckInfNan(snprintf, sscanf, "%s",
+              "[%F]", "[%+F]",
+              "[-INF]", "[INF]", "[+INF]",
+              "[-NAN]", "[NAN]", "[+NAN]");
+  CheckInfNan(snprintf, sscanf, "%s",
+              "[%g]", "[%+g]",
+              "[-inf]", "[inf]", "[+inf]",
+              "[-nan]", "[nan]", "[+nan]");
+  CheckInfNan(snprintf, sscanf, "%s",
+              "[%G]", "[%+G]",
+              "[-INF]", "[INF]", "[+INF]",
+              "[-NAN]", "[NAN]", "[+NAN]");
 }
 
-TEST(STDIO_TEST, wsprintf_inf_nan) {
-  CheckInfNan(swprintf, L"%a", L"%+a", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
-  CheckInfNan(swprintf, L"%A", L"%+A", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
-  CheckInfNan(swprintf, L"%e", L"%+e", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
-  CheckInfNan(swprintf, L"%E", L"%+E", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
-  CheckInfNan(swprintf, L"%f", L"%+f", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
-  CheckInfNan(swprintf, L"%F", L"%+F", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
-  CheckInfNan(swprintf, L"%g", L"%+g", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
-  CheckInfNan(swprintf, L"%G", L"%+G", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
+TEST(STDIO_TEST, swprintf_swscanf_inf_nan) {
+  CheckInfNan(swprintf, swscanf, L"%s",
+              L"[%a]", L"[%+a]",
+              L"[-inf]", L"[inf]", L"[+inf]",
+              L"[-nan]", L"[nan]", L"[+nan]");
+  CheckInfNan(swprintf, swscanf, L"%s",
+              L"[%A]", L"[%+A]",
+              L"[-INF]", L"[INF]", L"[+INF]",
+              L"[-NAN]", L"[NAN]", L"[+NAN]");
+  CheckInfNan(swprintf, swscanf, L"%s",
+              L"[%e]", L"[%+e]",
+              L"[-inf]", L"[inf]", L"[+inf]",
+              L"[-nan]", L"[nan]", L"[+nan]");
+  CheckInfNan(swprintf, swscanf, L"%s",
+              L"[%E]", L"[%+E]",
+              L"[-INF]", L"[INF]", L"[+INF]",
+              L"[-NAN]", L"[NAN]", L"[+NAN]");
+  CheckInfNan(swprintf, swscanf, L"%s",
+              L"[%f]", L"[%+f]",
+              L"[-inf]", L"[inf]", L"[+inf]",
+              L"[-nan]", L"[nan]", L"[+nan]");
+  CheckInfNan(swprintf, swscanf, L"%s",
+              L"[%F]", L"[%+F]",
+              L"[-INF]", L"[INF]", L"[+INF]",
+              L"[-NAN]", L"[NAN]", L"[+NAN]");
+  CheckInfNan(swprintf, swscanf, L"%s",
+              L"[%g]", L"[%+g]",
+              L"[-inf]", L"[inf]", L"[+inf]",
+              L"[-nan]", L"[nan]", L"[+nan]");
+  CheckInfNan(swprintf, swscanf, L"%s",
+              L"[%G]", L"[%+G]",
+              L"[-INF]", L"[INF]", L"[+INF]",
+              L"[-NAN]", L"[NAN]", L"[+NAN]");
 }
 
 TEST(STDIO_TEST, snprintf_d_INT_MAX) {
@@ -646,15 +730,34 @@
   fclose(fp);
 }
 
-TEST(STDIO_TEST, sscanf) {
-  char s1[123];
-  int i1;
-  double d1;
-  char s2[123];
-  ASSERT_EQ(3, sscanf("  hello 123 1.23 ", "%s %i %lf %s", s1, &i1, &d1, s2));
-  ASSERT_STREQ("hello", s1);
-  ASSERT_EQ(123, i1);
-  ASSERT_DOUBLE_EQ(1.23, d1);
+TEST(STDIO_TEST, sscanf_swscanf) {
+  struct stuff {
+    char s1[123];
+    int i1;
+    double d1;
+    float f1;
+    char s2[123];
+
+    void Check() {
+      ASSERT_STREQ("hello", s1);
+      ASSERT_EQ(123, i1);
+      ASSERT_DOUBLE_EQ(1.23, d1);
+      ASSERT_FLOAT_EQ(9.0f, f1);
+      ASSERT_STREQ("world", s2);
+    }
+  } s;
+
+  memset(&s, 0, sizeof(s));
+  ASSERT_EQ(5, sscanf("  hello 123 1.23 0x1.2p3 world",
+                      "%s %i %lf %f %s",
+                      s.s1, &s.i1, &s.d1, &s.f1, s.s2));
+  s.Check();
+
+  memset(&s, 0, sizeof(s));
+  ASSERT_EQ(5, swscanf(L"  hello 123 1.23 0x1.2p3 world",
+                       L"%s %i %lf %f %s",
+                       s.s1, &s.i1, &s.d1, &s.f1, s.s2));
+  s.Check();
 }
 
 TEST(STDIO_TEST, cantwrite_EBADF) {
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index 773230f..5b9442f 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -17,16 +17,18 @@
 #include <gtest/gtest.h>
 
 #include "BionicDeathTest.h"
+#include "math_data_test.h"
 #include "TemporaryFile.h"
 #include "utils.h"
 
 #include <errno.h>
+#include <fcntl.h>
 #include <libgen.h>
 #include <limits.h>
+#include <math.h>
 #include <pthread.h>
 #include <stdint.h>
 #include <stdlib.h>
-#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
@@ -288,16 +290,65 @@
   ASSERT_DOUBLE_EQ(1.23, atof("1.23"));
 }
 
+template <typename T>
+static void CheckStrToFloat(T fn(const char* s, char** end)) {
+  FpUlpEq<0, T> pred;
+
+  EXPECT_PRED_FORMAT2(pred, 9.0, fn("9.0", nullptr));
+  EXPECT_PRED_FORMAT2(pred, 9.0, fn("0.9e1", nullptr));
+  EXPECT_PRED_FORMAT2(pred, 9.0, fn("0x1.2p3", nullptr));
+
+  EXPECT_TRUE(isnan(fn("+nan", nullptr)));
+  EXPECT_TRUE(isnan(fn("nan", nullptr)));
+  EXPECT_TRUE(isnan(fn("-nan", nullptr)));
+
+  EXPECT_TRUE(isnan(fn("+nan(0xff)", nullptr)));
+  EXPECT_TRUE(isnan(fn("nan(0xff)", nullptr)));
+  EXPECT_TRUE(isnan(fn("-nan(0xff)", nullptr)));
+
+  char* p;
+  EXPECT_TRUE(isnan(fn("+nanny", &p)));
+  EXPECT_STREQ("ny", p);
+  EXPECT_TRUE(isnan(fn("nanny", &p)));
+  EXPECT_STREQ("ny", p);
+  EXPECT_TRUE(isnan(fn("-nanny", &p)));
+  EXPECT_STREQ("ny", p);
+
+  EXPECT_EQ(0, fn("muppet", &p));
+  EXPECT_STREQ("muppet", p);
+  EXPECT_EQ(0, fn("  muppet", &p));
+  EXPECT_STREQ("  muppet", p);
+
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("+inf", nullptr));
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("inf", nullptr));
+  EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn("-inf", nullptr));
+
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("+infinity", nullptr));
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("infinity", nullptr));
+  EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn("-infinity", nullptr));
+
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("+infinitude", &p));
+  EXPECT_STREQ("initude", p);
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("infinitude", &p));
+  EXPECT_STREQ("initude", p);
+  EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn("-infinitude", &p));
+  EXPECT_STREQ("initude", p);
+
+  // Check case-insensitivity.
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("InFiNiTy", nullptr));
+  EXPECT_TRUE(isnan(fn("NaN", nullptr)));
+}
+
 TEST(stdlib, strtod) {
-  ASSERT_DOUBLE_EQ(1.23, strtod("1.23", NULL));
+  CheckStrToFloat(strtod);
 }
 
 TEST(stdlib, strtof) {
-  ASSERT_FLOAT_EQ(1.23, strtof("1.23", NULL));
+  CheckStrToFloat(strtof);
 }
 
 TEST(stdlib, strtold) {
-  ASSERT_DOUBLE_EQ(1.23, strtold("1.23", NULL));
+  CheckStrToFloat(strtold);
 }
 
 TEST(stdlib, strtof_2206701) {
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 000dc98..db51c08 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -22,6 +22,8 @@
 #include <stdint.h>
 #include <wchar.h>
 
+#include "math_data_test.h"
+
 #define NUM_WCHARS(num_bytes) ((num_bytes)/sizeof(wchar_t))
 
 TEST(wchar, sizeof_wchar_t) {
@@ -389,14 +391,6 @@
   ASSERT_EQ('\x20', *invalid);
 }
 
-TEST(wchar, wcstod) {
-  ASSERT_DOUBLE_EQ(1.23, wcstod(L"1.23", NULL));
-}
-
-TEST(wchar, wcstof) {
-  ASSERT_FLOAT_EQ(1.23f, wcstof(L"1.23", NULL));
-}
-
 TEST(wchar, wcstol) {
   ASSERT_EQ(123L, wcstol(L"123", NULL, 0));
 }
@@ -405,10 +399,6 @@
   ASSERT_EQ(123LL, wcstol(L"123", NULL, 0));
 }
 
-TEST(wchar, wcstold) {
-  ASSERT_DOUBLE_EQ(1.23L, wcstold(L"1.23", NULL));
-}
-
 TEST(wchar, wcstoul) {
   ASSERT_EQ(123UL, wcstoul(L"123", NULL, 0));
 }
@@ -672,3 +662,64 @@
   wchar_t dst[6];
   ASSERT_EQ(&dst[4], wmempcpy(dst, L"hello", 4));
 }
+
+template <typename T>
+static void CheckWcsToFloat(T fn(const wchar_t* s, wchar_t** end)) {
+  FpUlpEq<0, T> pred;
+
+  EXPECT_PRED_FORMAT2(pred, 9.0, fn(L"9.0", nullptr));
+  EXPECT_PRED_FORMAT2(pred, 9.0, fn(L"0.9e1", nullptr));
+  EXPECT_PRED_FORMAT2(pred, 9.0, fn(L"0x1.2p3", nullptr));
+
+  EXPECT_TRUE(isnan(fn(L"+nan", nullptr)));
+  EXPECT_TRUE(isnan(fn(L"nan", nullptr)));
+  EXPECT_TRUE(isnan(fn(L"-nan", nullptr)));
+
+  EXPECT_TRUE(isnan(fn(L"+nan(0xff)", nullptr)));
+  EXPECT_TRUE(isnan(fn(L"nan(0xff)", nullptr)));
+  EXPECT_TRUE(isnan(fn(L"-nan(0xff)", nullptr)));
+
+  wchar_t* p;
+  EXPECT_TRUE(isnan(fn(L"+nanny", &p)));
+  EXPECT_STREQ(L"ny", p);
+  EXPECT_TRUE(isnan(fn(L"nanny", &p)));
+  EXPECT_STREQ(L"ny", p);
+  EXPECT_TRUE(isnan(fn(L"-nanny", &p)));
+  EXPECT_STREQ(L"ny", p);
+
+  EXPECT_EQ(0, fn(L"muppet", &p));
+  EXPECT_STREQ(L"muppet", p);
+  EXPECT_EQ(0, fn(L"  muppet", &p));
+  EXPECT_STREQ(L"  muppet", p);
+
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"+inf", nullptr));
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"inf", nullptr));
+  EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn(L"-inf", nullptr));
+
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"+infinity", nullptr));
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"infinity", nullptr));
+  EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn(L"-infinity", nullptr));
+
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"+infinitude", &p));
+  EXPECT_STREQ(L"initude", p);
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"infinitude", &p));
+  EXPECT_STREQ(L"initude", p);
+  EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn(L"-infinitude", &p));
+  EXPECT_STREQ(L"initude", p);
+
+  // Check case-insensitivity.
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"InFiNiTy", nullptr));
+  EXPECT_TRUE(isnan(fn(L"NaN", nullptr)));
+}
+
+TEST(wchar, wcstod) {
+  CheckWcsToFloat(wcstod);
+}
+
+TEST(wchar, wcstof) {
+  CheckWcsToFloat(wcstof);
+}
+
+TEST(wchar, wcstold) {
+  CheckWcsToFloat(wcstold);
+}