Berry fix integer and real parser to handle overflows (#23495)

This commit is contained in:
s-hadinger 2025-05-31 15:03:54 +02:00 committed by GitHub
parent fcf4706914
commit 1cd4e27123
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 83 additions and 17 deletions

View File

@ -28,6 +28,7 @@ All notable changes to this project will be documented in this file.
- ESP32-S3 display stability regression from #23397 (#23404)
- DNS setting with `IPAddress4/5` not persisted (#23426)
- Berry avoid json parsing for unmatched commands
- Berry fix integer and real parser to handle overflows
### Removed

View File

@ -16,6 +16,28 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#include <float.h>
#include <math.h>
#if BE_INTGER_TYPE == 0 /* int */
#define M_IMAX INT_MAX
#define M_IMIN INT_MIN
#elif BE_INTGER_TYPE == 1 /* long */
#define M_IMAX LONG_MAX
#define M_IMIN LONG_MIN
#else /* int64_t (long long) */
#define M_IMAX LLONG_MAX
#define M_IMIN LLONG_MIN
#endif
#if BE_USE_SINGLE_FLOAT == 0 /* double */
#define BREAL_MAX DBL_MAX
#define BREAL_MIN DBL_MIN
#else
#define BREAL_MAX FLT_MAX
#define BREAL_MIN FLT_MIN
#endif
#define is_space(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
#define is_digit(c) ((c) >= '0' && (c) <= '9')
@ -279,7 +301,9 @@ BERRY_API bint be_str2int(const char *str, const char **endstr)
/* hex literal */
str += 2; /* skip 0x or 0X */
while ((c = be_char2hex(*str++)) >= 0) {
if (sum > M_IMAX / 16) goto overflow_pos;
sum = sum * 16 + c;
if (sum < 0) goto overflow_pos; /* overflow check */
}
if (endstr) {
*endstr = str - 1;
@ -292,14 +316,30 @@ BERRY_API bint be_str2int(const char *str, const char **endstr)
c = *str++;
}
while (is_digit(c)) {
sum = sum * 10 + c - '0';
if (sign == '-') {
if (sum < M_IMIN / 10) goto overflow_neg;
sum = sum * 10 - (c - '0');
if (sum > 0) goto overflow_neg; /* overflow check */
} else {
if (sum > M_IMAX / 10) goto overflow_pos;
sum = sum * 10 + (c - '0');
if (sum < 0) goto overflow_pos; /* overflow check */
}
c = *str++;
}
if (endstr) {
*endstr = str - 1;
}
return sign == '-' ? -sum : sum;
return sum;
}
overflow_pos:
if (endstr) *endstr = str - 1;
return M_IMAX;
overflow_neg:
if (endstr) *endstr = str - 1;
return M_IMIN;
}
/*******************************************************************
@ -317,42 +357,67 @@ BERRY_API breal be_str2real(const char *str, const char **endstr)
{
int c, sign;
breal sum = 0, deci = 0, point = (breal)0.1;
skip_space(str);
sign = c = *str++;
if (c == '+' || c == '-') {
c = *str++;
}
if (c == '+' || c == '-') c = *str++; /* skip sign if present */
/* Integer part with overflow check */
while (is_digit(c)) {
sum = sum * 10 + c - '0';
if (sum > BREAL_MAX / 10) goto overflow;
sum = sum * 10 + (c - '0');
if (sum > BREAL_MAX) goto overflow;
c = *str++;
}
/* Fractional part */
if (c == '.') {
c = *str++;
while (is_digit(c)) {
deci = deci + ((breal)c - '0') * point;
breal digit = (c - '0') * point;
if (deci + digit < deci) break; /* precision limit reached */
deci += digit;
point *= (breal)0.1;
c = *str++;
}
}
sum = sum + deci;
sum += deci;
if (sum > BREAL_MAX) goto overflow;
/* Scientific notation */
if (c == 'e' || c == 'E') {
int e = 0;
breal ratio = (c = *str++) == '-' ? (breal)0.1 : 10;
if (c == '+' || c == '-') {
int e = 0, esign = 1;
c = *str++;
}
if (c == '-') { esign = -1; c = *str++; }
else if (c == '+') c = *str++;
while (is_digit(c)) {
e = e * 10 + c - '0';
if (e > 300) goto overflow;
e = e * 10 + (c - '0');
c = *str++;
}
e *= esign;
breal ratio = (e < 0) ? (breal)0.1 : 10;
if (e < 0) e = -e;
while (e--) {
if (e > 0 && sum > BREAL_MAX / ratio) goto overflow;
sum *= ratio;
}
}
if (endstr) {
*endstr = str - 1;
}
if (endstr) *endstr = str - 1;
return sign == '-' ? -sum : sum;
overflow:
if (endstr) *endstr = str - 1;
#if BE_USE_SINGLE_FLOAT == 0
return sign == '-' ? -HUGE_VAL : HUGE_VAL;
#else
return sign == '-' ? -HUGE_VALF : HUGE_VALF;
#endif
}
/* convert a string to a number (integer or real).