[libc] fix strtol returning the wrong length

Previously, strtol/ll/ul/ull would return a pointer to the end of its
parsing, regardless of if it detected a number. Now it will return a
length of 0 when it doesn't find a number.

Reviewed By: sivachandra

Differential Revision: https://reviews.llvm.org/D112176
This commit is contained in:
Michael Jones 2021-10-20 13:08:46 -07:00
parent 2feafa2e46
commit 53804d4eb2
5 changed files with 140 additions and 9 deletions

View File

@ -42,15 +42,23 @@ static inline bool is_hex_start(const char *__restrict src) {
}
// 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 @@ template <class T>
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 @@ static inline T strtointeger(const char *__restrict src,
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 @@ static inline T strtointeger(const char *__restrict src,
}
if (str_end != nullptr)
*str_end = const_cast<char *>(src);
*str_end = const_cast<char *>(is_number ? src : original_src);
if (result == ABS_MAX) {
if (is_positive || is_unsigned)

View File

@ -118,7 +118,7 @@ TEST(LlvmLibcStrToLTest, MessyBaseTenDecode) {
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 @@ TEST(LlvmLibcStrToLTest, MessyBaseTenDecode) {
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 @@ TEST(LlvmLibcStrToLTest, AutomaticBaseSelection) {
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));
}

View File

@ -142,7 +142,7 @@ TEST(LlvmLibcStrToLLTest, MessyBaseTenDecode) {
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 @@ TEST(LlvmLibcStrToLLTest, MessyBaseTenDecode) {
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 @@ TEST(LlvmLibcStrToLLTest, AutomaticBaseSelection) {
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));
}

View File

@ -110,7 +110,7 @@ TEST(LlvmLibcStrToULTest, MessyBaseTenDecode) {
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 @@ TEST(LlvmLibcStrToULTest, MessyBaseTenDecode) {
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 @@ TEST(LlvmLibcStrToULTest, AutomaticBaseSelection) {
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));
}

View File

@ -118,7 +118,7 @@ TEST(LlvmLibcStrToULLTest, MessyBaseTenDecode) {
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 @@ TEST(LlvmLibcStrToULLTest, MessyBaseTenDecode) {
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 @@ TEST(LlvmLibcStrToULLTest, AutomaticBaseSelection) {
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));
}