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 @@ -42,15 +42,23 @@ } // Takes the address of the string pointer and parses the base from the start of -// it. This will advance the string pointer. +// it. This function will advance |src| to the first valid digit in the inferred +// base. static inline int infer_base(const char *__restrict *__restrict src) { + // A hexadecimal number is defined as "the prefix 0x or 0X followed by a + // sequence of the deimal digits and the letters a (or A) through f (or F) + // with values 10 through 15 respectively." (C standard 6.4.4.1) if (is_hex_start(*src)) { (*src) += 2; return 16; - } else if (**src == '0') { - ++(*src); + } // An octal number is defined as "the prefix 0 optionally followed by a + // sequence of the digits 0 through 7 only" (C standard 6.4.4.1) and so any + // number that starts with 0, including just 0, is an octal number. + else if (**src == '0') { return 8; - } else { + } // A decimal number is defined as beginning "with a nonzero digit and + // consist[ing] of a sequence of decimal digits." (C standard 6.4.4.1) + else { return 10; } } @@ -62,6 +70,8 @@ static inline T strtointeger(const char *__restrict src, char **__restrict str_end, int base) { unsigned long long result = 0; + bool is_number = false; + const char *original_src = src; if (base < 0 || base == 1 || base > 36) { errno = EINVAL; // NOLINT @@ -97,6 +107,7 @@ if (cur_digit >= base) break; + is_number = true; ++src; // If the number has already hit the maximum value for the current type then @@ -122,7 +133,7 @@ } if (str_end != nullptr) - *str_end = const_cast(src); + *str_end = const_cast(is_number ? 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) { @@ -322,4 +334,22 @@ ASSERT_EQ(__llvm_libc::strtol(base_eight_with_prefix, &str_end, 0), 012345l); ASSERT_EQ(errno, 0); EXPECT_EQ(str_end - base_eight_with_prefix, ptrdiff_t(6)); + + const char *just_zero = "0"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtol(just_zero, &str_end, 0), 0l); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero, ptrdiff_t(1)); + + const char *just_zero_x = "0x"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtol(just_zero_x, &str_end, 0), 0l); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero_x, ptrdiff_t(1)); + + const char *just_zero_eight = "08"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtol(just_zero_eight, &str_end, 0), 0l); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero_eight, ptrdiff_t(1)); } 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) { @@ -350,4 +362,22 @@ 012345ll); ASSERT_EQ(errno, 0); EXPECT_EQ(str_end - base_eight_with_prefix, ptrdiff_t(6)); + + const char *just_zero = "0"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoll(just_zero, &str_end, 0), 0ll); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero, ptrdiff_t(1)); + + const char *just_zero_x = "0x"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoll(just_zero_x, &str_end, 0), 0ll); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero_x, ptrdiff_t(1)); + + const char *just_zero_eight = "08"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoll(just_zero_eight, &str_end, 0), 0ll); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero_eight, ptrdiff_t(1)); } 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) { @@ -318,4 +330,22 @@ 012345ul); ASSERT_EQ(errno, 0); EXPECT_EQ(str_end - base_eight_with_prefix, ptrdiff_t(6)); + + const char *just_zero = "0"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoul(just_zero, &str_end, 0), 0ul); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero, ptrdiff_t(1)); + + const char *just_zero_x = "0x"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoul(just_zero_x, &str_end, 0), 0ul); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero_x, ptrdiff_t(1)); + + const char *just_zero_eight = "08"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoul(just_zero_eight, &str_end, 0), 0ul); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero_eight, ptrdiff_t(1)); } 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) { @@ -326,4 +338,22 @@ 012345ull); ASSERT_EQ(errno, 0); EXPECT_EQ(str_end - base_eight_with_prefix, ptrdiff_t(6)); + + const char *just_zero = "0"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoull(just_zero, &str_end, 0), 0ull); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero, ptrdiff_t(1)); + + const char *just_zero_x = "0x"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoull(just_zero_x, &str_end, 0), 0ull); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero_x, ptrdiff_t(1)); + + const char *just_zero_eight = "08"; + errno = 0; + ASSERT_EQ(__llvm_libc::strtoull(just_zero_eight, &str_end, 0), 0ull); + ASSERT_EQ(errno, 0); + EXPECT_EQ(str_end - just_zero_eight, ptrdiff_t(1)); }