Skip to content

Commit 66131c0

Browse files
hartbitstephentyrone
authored andcommitted
[SR-2626] Fix String to Float/Double “snan” conversion (#8036)
Adds an explicit check for `[+-]snan` to create an sNaN from a string.
1 parent 7d5ac5e commit 66131c0

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

stdlib/public/stubs/Stubs.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,12 +444,29 @@ __mulodi4(di_int a, di_int b, int* overflow)
444444
}
445445
#endif
446446

447+
#if defined(__CYGWIN__) || defined(_WIN32)
448+
#define strcasecmp _stricmp
449+
#endif
450+
451+
static bool swift_stringIsSignalingNaN(const char *nptr) {
452+
if (nptr[0] == '+' || nptr[0] == '-') {
453+
nptr++;
454+
}
455+
456+
return strcasecmp(nptr, "snan") == 0;
457+
}
458+
447459
#if defined(__CYGWIN__) || defined(_WIN32)
448460
// Cygwin does not support uselocale(), but we can use the locale feature
449461
// in stringstream object.
450462
template <typename T>
451463
static const char *_swift_stdlib_strtoX_clocale_impl(
452464
const char *nptr, T *outResult) {
465+
if (swift_stringIsSignalingNaN(nptr)) {
466+
*outResult = std::numeric_limits<T>::signaling_NaN();
467+
return nptr + std::strlen(nptr);
468+
}
469+
453470
std::istringstream ValueStream(nptr);
454471
ValueStream.imbue(std::locale::classic());
455472
T ParsedValue;
@@ -487,6 +504,13 @@ static const char *_swift_stdlib_strtoX_clocale_impl(
487504
const char * nptr, T* outResult, T huge,
488505
T (*posixImpl)(const char *, char **, locale_t)
489506
) {
507+
if (swift_stringIsSignalingNaN(nptr)) {
508+
// TODO: ensure that the returned sNaN bit pattern matches that of sNaNs
509+
// produced by Swift.
510+
*outResult = std::numeric_limits<T>::signaling_NaN();
511+
return nptr + std::strlen(nptr);
512+
}
513+
490514
char *EndPtr;
491515
errno = 0;
492516
const auto result = posixImpl(nptr, &EndPtr, getCLocale());

test/stdlib/NumericParsing.swift.gyb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ tests.test("${Self}/Basics") {
135135
expectEqual(-(.infinity), ${Self}("-Inf"))
136136
expectEqual(String(${Self}.nan), String(${Self}("nan")!))
137137
expectEqual(String(${Self}.nan), String(${Self}("NaN")!))
138+
139+
// sNaN cannot be fully supported on i386.
140+
#if !arch(i386)
141+
expectTrue(${Self}("sNaN")!.isSignalingNaN)
142+
expectTrue(${Self}("SNAN")!.isSignalingNaN)
143+
expectTrue(${Self}("+snan")!.isSignalingNaN)
144+
expectTrue(${Self}("-SnAn")!.isSignalingNaN)
145+
#endif
138146
% end
139147

140148
expectEqual(-0.0, ${Self}("-0"))

0 commit comments

Comments
 (0)