Commit a639c412 authored by Kenton Varda's avatar Kenton Varda

Work around strtod("nan") behavior on Windows.

Windows -- including Cygwin -- return a NaN representation with the sign bit set, whereas other platforms return one without the sign bit set. This results in different binary output in the JSON-to-binary part of capnp-test.sh.

This was uncovered since we're now runing capnp-test.sh for Cygwin builds, but the problem actually applies to *all* Windows builds. We just weren't running this test for the other builds before.

Interestingly, I *had* run this test with a MinGW cross-compile build running on WINE, and it passed there. Seemingly, WINE's strtod() directly wraps the host system's without trying to emulate Windows differences.
parent 3a184591
......@@ -216,6 +216,21 @@ KJ_TEST("kj::delimited() and kj::strPreallocated()") {
}
}
KJ_TEST("parsing 'nan' returns canonical NaN value") {
// There are many representations of NaN. We would prefer that parsing "NaN" produces exactly the
// same bits that kj::nan() returns.
{
double parsedNan = StringPtr("NaN").parseAs<double>();
double canonicalNan = kj::nan();
KJ_EXPECT(memcmp(&parsedNan, &canonicalNan, sizeof(parsedNan)) == 0);
}
{
float parsedNan = StringPtr("NaN").parseAs<float>();
float canonicalNan = kj::nan();
KJ_EXPECT(memcmp(&parsedNan, &canonicalNan, sizeof(parsedNan)) == 0);
}
}
} // namespace
} // namespace _ (private)
} // namespace kj
......@@ -82,6 +82,19 @@ double parseDouble(const StringPtr& s) {
errno = 0;
auto value = strtod(s.begin(), &endPtr);
KJ_REQUIRE(endPtr == s.end(), "String does not contain valid floating number", s) { return 0; }
#if _WIN32 || __CYGWIN__
// When Windows' strtod() parses "nan", it returns a value with the sign bit set. But, our
// preferred canonical value for NaN does not have the sign bit set, and all other platforms
// return one without the sign bit set. So, on Windows, detect NaN and return our preferred
// version.
//
// Cygwin seemingly does not try to emulate Linux behavior here, but rather allows Windows'
// behavior to leak through.
if (isNaN(value)) {
// NaN
return kj::nan();
}
#endif
return value;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment