mirror of
https://github.com/redis/redis.git
synced 2026-06-08 16:24:26 -04:00
Adjust fastfloat tests for libc-dependent nan payload parsing (#15110)
## Problem `strtod()` handles some `nan(n-char-sequence)` inputs differently across libc implementations. For example, `nan(ab!c)` and `nan(ab c)` may be accepted on some platforms but rejected on others. The existing test treated these inputs as fixed invalid cases, which can fail on platforms whose libc accepts them. ## Changes - Move libc-dependent `nan(...)` cases out of the fixed invalid test list. - Add a helper to verify `fast_float_strtod()` matches the platform `strtod()` behavior for these cases, including value, `endptr`, and success/failure status. - Keep the existing parser behavior unchanged. --------- Co-authored-by: debing.sun <debing.sun@redis.com>
This commit is contained in:
parent
fa08257fcb
commit
f023cf026b
1 changed files with 36 additions and 4 deletions
|
|
@ -780,6 +780,11 @@ static int ff_eq(double a, double b) {
|
|||
return a == b;
|
||||
}
|
||||
|
||||
static int is_parse_failed(const char *s, size_t len, const char *eptr, int err, double d) {
|
||||
return ((size_t)(eptr - s) != len) || err == EINVAL ||
|
||||
(err == ERANGE && (d == HUGE_VAL || d == -HUGE_VAL || fpclassify(d) == FP_ZERO));
|
||||
}
|
||||
|
||||
static void run_ff_tests(ff_testcase *cases, int n, int expect_failed) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
const char *s = cases[i].input;
|
||||
|
|
@ -788,8 +793,7 @@ static void run_ff_tests(ff_testcase *cases, int n, int expect_failed) {
|
|||
|
||||
errno = 0;
|
||||
double d = fast_float_strtod(s, len, &eptr);
|
||||
int failed = ((size_t)(eptr - s) != len) || errno == EINVAL ||
|
||||
(errno == ERANGE && (d == HUGE_VAL || d == -HUGE_VAL || fpclassify(d) == FP_ZERO));
|
||||
int failed = is_parse_failed(s, len, eptr, errno, d);
|
||||
int ok = (expect_failed == failed) && ff_eq(d, cases[i].expected);
|
||||
char descr[128];
|
||||
if (ok)
|
||||
|
|
@ -802,6 +806,28 @@ static void run_ff_tests(ff_testcase *cases, int n, int expect_failed) {
|
|||
}
|
||||
}
|
||||
|
||||
static void run_ff_libc_compat_tests(const char **cases, int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
const char *s = cases[i];
|
||||
size_t len = strlen(s);
|
||||
char *eptr, *libc_eptr;
|
||||
|
||||
errno = 0;
|
||||
double d = fast_float_strtod(s, len, &eptr);
|
||||
int err = errno;
|
||||
|
||||
errno = 0;
|
||||
double libc_d = strtod(s, &libc_eptr);
|
||||
int libc_err = errno;
|
||||
|
||||
int failed = is_parse_failed(s, len, eptr, err, d);
|
||||
int libc_failed = is_parse_failed(s, len, libc_eptr, libc_err, libc_d);
|
||||
char descr[128];
|
||||
snprintf(descr, sizeof(descr), "ff matches libc strtod: \"%s\"", s);
|
||||
test_cond(descr, failed == libc_failed && (eptr - s) == (libc_eptr - s) && ff_eq(d, libc_d));
|
||||
}
|
||||
}
|
||||
|
||||
int fastFloatTest(int argc, char **argv, int flags) {
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
|
@ -1015,8 +1041,6 @@ int fastFloatTest(int argc, char **argv, int flags) {
|
|||
{"na", 0},
|
||||
{"nan(", NAN}, /* unclosed paren */
|
||||
{"nan(abc", NAN}, /* missing closing paren */
|
||||
{"nan(ab!c)", NAN}, /* invalid char in paren */
|
||||
{"nan(ab c)", NAN}, /* space in paren */
|
||||
{"nanx", NAN}, /* trailing garbage */
|
||||
};
|
||||
run_ff_tests(nan_invalid, COUNTOF(nan_invalid), 1);
|
||||
|
|
@ -1043,6 +1067,14 @@ int fastFloatTest(int argc, char **argv, int flags) {
|
|||
eptr == big && ff_eq(d, 0.0));
|
||||
}
|
||||
|
||||
/* The accepted character set for nan(n-char-sequence) is libc-dependent.
|
||||
* Preserve strtod-compatible behavior instead of asserting a fixed result. */
|
||||
const char *nan_libc_compat[] = {
|
||||
"nan(ab!c)",
|
||||
"nan(ab c)",
|
||||
};
|
||||
run_ff_libc_compat_tests(nan_libc_compat, COUNTOF(nan_libc_compat));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue