mirror of
https://github.com/RGBCube/serenity
synced 2025-07-05 13:07:35 +00:00
LibC: Fix strtol() handling of invalid characters
Rewrite this function to go from left-to-right instead of right-to-left since this allows us to accumulate valid characters before encountering any invalid ones. This fixes parsing of strings emitted by GCC, like "1, %0|%0, %1}". :^)
This commit is contained in:
parent
56eaf9b033
commit
d3a8fe70a2
1 changed files with 69 additions and 29 deletions
|
@ -329,49 +329,89 @@ size_t mbstowcs(wchar_t*, const char*, size_t)
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
long strtol(const char* str, char** endptr, int base)
|
long strtol(const char* nptr, char** endptr, int base)
|
||||||
{
|
{
|
||||||
int sign = 1;
|
errno = 0;
|
||||||
while (isspace(*str))
|
|
||||||
str++;
|
if (base < 0 || base == 1 || base > 36) {
|
||||||
if (*str == '-' || *str == '+') {
|
errno = EINVAL;
|
||||||
if (*str == '-')
|
if (endptr)
|
||||||
sign = -1;
|
*endptr = const_cast<char*>(nptr);
|
||||||
str++;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* p = nptr;
|
||||||
|
while (isspace(*p))
|
||||||
|
++p;
|
||||||
|
|
||||||
|
bool is_negative = false;
|
||||||
|
if (*p == '-') {
|
||||||
|
is_negative = true;
|
||||||
|
++p;
|
||||||
|
} else {
|
||||||
|
if (*p == '+')
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
if (base == 0 || base == 16) {
|
if (base == 0 || base == 16) {
|
||||||
if (base == 0)
|
if (base == 0)
|
||||||
base = 10;
|
base = 10;
|
||||||
if (*str == '0') {
|
if (*p == '0') {
|
||||||
str++;
|
if (*(p + 1) == 'X' || *(p + 1) == 'x') {
|
||||||
if (*str == 'X' || *str == 'x') {
|
p += 2;
|
||||||
str++;
|
|
||||||
base = 16;
|
base = 16;
|
||||||
} else if (base != 16) {
|
} else if (base != 16) {
|
||||||
base = 8;
|
base = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t length = strlen(str);
|
|
||||||
const char* estr = str + length - 1;
|
long cutoff_point = is_negative ? (LONG_MIN / base) : (LONG_MAX / base);
|
||||||
long track = 1;
|
int max_valid_digit_at_cutoff_point = is_negative ? (LONG_MIN % base) : (LONG_MAX % base);
|
||||||
|
|
||||||
long num = 0;
|
long num = 0;
|
||||||
while (estr >= str) {
|
|
||||||
if ((*estr >= '0' && *estr <= '9') || (base > 10 && (*estr >= 'A' && *estr <= 'Z'))) {
|
bool has_overflowed = false;
|
||||||
int digit_value = *estr - '0';
|
unsigned digits_consumed = 0;
|
||||||
if (*estr >= 'A' && *estr <= 'Z')
|
|
||||||
digit_value = 10 + (*estr - 'A');
|
for (;;) {
|
||||||
num += (track *= base) / base * digit_value;
|
char ch = *(p++);
|
||||||
|
int digit;
|
||||||
|
if (isdigit(ch))
|
||||||
|
digit = ch - '0';
|
||||||
|
else if (islower(ch))
|
||||||
|
digit = ch - ('a' - 10);
|
||||||
|
else if (isupper(ch))
|
||||||
|
digit = ch - ('A' - 10);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (digit >= base)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (has_overflowed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool is_past_cutoff = is_negative ? num < cutoff_point : num > cutoff_point;
|
||||||
|
|
||||||
|
if (is_past_cutoff || (num == cutoff_point && digit > max_valid_digit_at_cutoff_point)) {
|
||||||
|
has_overflowed = true;
|
||||||
|
num = is_negative ? LONG_MIN : LONG_MAX;
|
||||||
|
errno = ERANGE;
|
||||||
} else {
|
} else {
|
||||||
if (endptr)
|
num *= base;
|
||||||
*endptr = const_cast<char*>(estr);
|
num += is_negative ? -digit : digit;
|
||||||
return 0;
|
++digits_consumed;
|
||||||
};
|
|
||||||
estr--;
|
|
||||||
}
|
}
|
||||||
if (endptr)
|
}
|
||||||
*endptr = const_cast<char*>(str + length);
|
|
||||||
return num * sign;
|
if (endptr) {
|
||||||
|
if (has_overflowed || digits_consumed > 0)
|
||||||
|
*endptr = const_cast<char*>(p - 1);
|
||||||
|
else
|
||||||
|
*endptr = const_cast<char*>(nptr);
|
||||||
|
}
|
||||||
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long strtoul(const char* str, char** endptr, int base)
|
unsigned long strtoul(const char* str, char** endptr, int base)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue