diff --git a/libc/src/__support/str_conv_utils.h b/libc/src/__support/str_conv_utils.h --- a/libc/src/__support/str_conv_utils.h +++ b/libc/src/__support/str_conv_utils.h @@ -62,6 +62,8 @@ static inline T strtointeger(const char *__restrict src, char **__restrict str_end, int base) { unsigned long long result = 0; + bool seen_digit = false; + const char *original_src = src; if (base < 0 || base == 1 || base > 36) { errno = EINVAL; // NOLINT @@ -76,6 +78,10 @@ ++src; } + if (*src == '0' || (isalnum(*src) && b36_char_to_int(*src) < base)) { + seen_digit = true; + } + if (base == 0) { base = infer_base(&src); } else if (base == 16 && is_hex_start(src)) { @@ -97,6 +103,7 @@ if (cur_digit >= base) break; + seen_digit = true; ++src; // If the number has already hit the maximum value for the current type then @@ -122,7 +129,7 @@ } if (str_end != nullptr) - *str_end = const_cast(src); + *str_end = const_cast(seen_digit ? src : original_src); if (result == ABS_MAX) { if (is_positive || is_unsigned) diff --git a/libc/test/src/stdlib/strtol_test.cpp b/libc/test/src/stdlib/strtol_test.cpp --- a/libc/test/src/stdlib/strtol_test.cpp +++ b/libc/test/src/stdlib/strtol_test.cpp @@ -118,7 +118,7 @@ errno = 0; ASSERT_EQ(__llvm_libc::strtol(two_signs, &str_end, 10), 0l); ASSERT_EQ(errno, 0); - EXPECT_EQ(str_end - two_signs, ptrdiff_t(1)); + EXPECT_EQ(str_end - two_signs, ptrdiff_t(0)); const char *sign_before = "+2=4"; errno = 0; @@ -143,6 +143,18 @@ ASSERT_EQ(__llvm_libc::strtol(all_together, &str_end, 10), -12345l); ASSERT_EQ(errno, 0); EXPECT_EQ(str_end - all_together, ptrdiff_t(9)); + + const char *just_spaces = " "; + errno = 0; + ASSERT_EQ(__llvm_libc::strtol(just_spaces, &str_end, 10), 0l); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_spaces, ptrdiff_t(0)); + + const char *just_space_and_sign = " +"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtol(just_space_and_sign, &str_end, 10), 0l); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_space_and_sign, ptrdiff_t(0)); } static char int_to_b36_char(int input) { diff --git a/libc/test/src/stdlib/strtoll_test.cpp b/libc/test/src/stdlib/strtoll_test.cpp --- a/libc/test/src/stdlib/strtoll_test.cpp +++ b/libc/test/src/stdlib/strtoll_test.cpp @@ -142,7 +142,7 @@ errno = 0; ASSERT_EQ(__llvm_libc::strtoll(two_signs, &str_end, 10), 0ll); ASSERT_EQ(errno, 0); - EXPECT_EQ(str_end - two_signs, ptrdiff_t(1)); + EXPECT_EQ(str_end - two_signs, ptrdiff_t(0)); const char *sign_before = "+2=4"; errno = 0; @@ -167,6 +167,18 @@ ASSERT_EQ(__llvm_libc::strtoll(all_together, &str_end, 10), -12345ll); ASSERT_EQ(errno, 0); EXPECT_EQ(str_end - all_together, ptrdiff_t(9)); + + const char *just_spaces = " "; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoll(just_spaces, &str_end, 10), 0ll); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_spaces, ptrdiff_t(0)); + + const char *just_space_and_sign = " +"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoll(just_space_and_sign, &str_end, 10), 0ll); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_space_and_sign, ptrdiff_t(0)); } static char int_to_b36_char(int input) { diff --git a/libc/test/src/stdlib/strtoul_test.cpp b/libc/test/src/stdlib/strtoul_test.cpp --- a/libc/test/src/stdlib/strtoul_test.cpp +++ b/libc/test/src/stdlib/strtoul_test.cpp @@ -110,7 +110,7 @@ errno = 0; ASSERT_EQ(__llvm_libc::strtoul(two_signs, &str_end, 10), 0ul); ASSERT_EQ(errno, 0); - EXPECT_EQ(str_end - two_signs, ptrdiff_t(1)); + EXPECT_EQ(str_end - two_signs, ptrdiff_t(0)); const char *sign_before = "+2=4"; errno = 0; @@ -135,6 +135,18 @@ ASSERT_EQ(__llvm_libc::strtoul(all_together, &str_end, 10), -(12345ul)); ASSERT_EQ(errno, 0); EXPECT_EQ(str_end - all_together, ptrdiff_t(9)); + + const char *just_spaces = " "; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoul(just_spaces, &str_end, 10), 0ul); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_spaces, ptrdiff_t(0)); + + const char *just_space_and_sign = " +"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoul(just_space_and_sign, &str_end, 10), 0ul); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_space_and_sign, ptrdiff_t(0)); } static char int_to_b36_char(int input) { diff --git a/libc/test/src/stdlib/strtoull_test.cpp b/libc/test/src/stdlib/strtoull_test.cpp --- a/libc/test/src/stdlib/strtoull_test.cpp +++ b/libc/test/src/stdlib/strtoull_test.cpp @@ -118,7 +118,7 @@ errno = 0; ASSERT_EQ(__llvm_libc::strtoull(two_signs, &str_end, 10), 0ull); ASSERT_EQ(errno, 0); - EXPECT_EQ(str_end - two_signs, ptrdiff_t(1)); + EXPECT_EQ(str_end - two_signs, ptrdiff_t(0)); const char *sign_before = "+2=4"; errno = 0; @@ -143,6 +143,18 @@ ASSERT_EQ(__llvm_libc::strtoull(all_together, &str_end, 10), -(12345ull)); ASSERT_EQ(errno, 0); EXPECT_EQ(str_end - all_together, ptrdiff_t(9)); + + const char *just_spaces = " "; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoull(just_spaces, &str_end, 10), 0ull); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_spaces, ptrdiff_t(0)); + + const char *just_space_and_sign = " +"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoull(just_space_and_sign, &str_end, 10), 0ull); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_space_and_sign, ptrdiff_t(0)); } static char int_to_b36_char(int input) {