Fix wcsto* where strings begin with whitespace.
The libc++ tests caught this.
Test: adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
Bug: None
Change-Id: I14864e006f6cf9de3f96acac6aa3eb235894f2b1
diff --git a/libc/bionic/wcstod.cpp b/libc/bionic/wcstod.cpp
index eb66ba0..f7bd433 100644
--- a/libc/bionic/wcstod.cpp
+++ b/libc/bionic/wcstod.cpp
@@ -32,8 +32,14 @@
#include "local.h"
-template <typename float_type> float_type wcstod(const wchar_t* str, wchar_t** end,
- float_type strtod_fn(const char*, char**)) {
+/// Performs wide-character string to floating point conversion.
+template <typename float_type>
+float_type wcstod(const wchar_t* str, wchar_t** end, float_type strtod_fn(const char*, char**)) {
+ const wchar_t* original_str = str;
+ while (iswspace(*str)) {
+ str++;
+ }
+
// What's the longest span of the input that might be part of the float?
size_t max_len = wcsspn(str, L"-+0123456789.xXeEpP()nNaAiIfFtTyY");
@@ -70,7 +76,15 @@
float_type result = strtod_fn(ascii_str, &ascii_end);
if (ascii_end != ascii_str + actual_len) abort();
- if (end) *end = const_cast<wchar_t*>(str) + actual_len;
+ if (end) {
+ if (actual_len == 0) {
+ // There was an error. We need to set the end pointer back to the original string, not the
+ // one we advanced past the leading whitespace.
+ *end = const_cast<wchar_t*>(original_str);
+ } else {
+ *end = const_cast<wchar_t*>(str) + actual_len;
+ }
+ }
delete[] ascii_str;
return result;
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index 5b9442f..fc17cde 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -298,6 +298,11 @@
EXPECT_PRED_FORMAT2(pred, 9.0, fn("0.9e1", nullptr));
EXPECT_PRED_FORMAT2(pred, 9.0, fn("0x1.2p3", nullptr));
+ const char* s = " \t\v\f\r\n9.0";
+ char* p;
+ EXPECT_PRED_FORMAT2(pred, 9.0, fn(s, &p));
+ EXPECT_EQ(s + strlen(s), p);
+
EXPECT_TRUE(isnan(fn("+nan", nullptr)));
EXPECT_TRUE(isnan(fn("nan", nullptr)));
EXPECT_TRUE(isnan(fn("-nan", nullptr)));
@@ -306,7 +311,6 @@
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)));
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 34ed5a7..830eb70 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -686,6 +686,11 @@
EXPECT_PRED_FORMAT2(pred, 9.0, fn(L"0.9e1", nullptr));
EXPECT_PRED_FORMAT2(pred, 9.0, fn(L"0x1.2p3", nullptr));
+ const wchar_t* s = L" \t\v\f\r\n9.0";
+ wchar_t* p;
+ EXPECT_PRED_FORMAT2(pred, 9.0, fn(s, &p));
+ EXPECT_EQ(s + wcslen(s), p);
+
EXPECT_TRUE(isnan(fn(L"+nan", nullptr)));
EXPECT_TRUE(isnan(fn(L"nan", nullptr)));
EXPECT_TRUE(isnan(fn(L"-nan", nullptr)));
@@ -694,7 +699,6 @@
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)));