mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
fp_uscale.c: fix uninitialized *fp when exponent is malformed
mrb_read_float jumped past the *fp assignment via `goto done` when
the exponent had no digits (e.g., "5e", "5e+"). It returned TRUE
without setting *fp, leaving the caller (mrb_str_to_dbl etc.) to
return whatever was on the stack. MSan flagged this; on most runs
the uninitialized read happens to yield 0.0, so the bug is silently
incorrect rather than crashing.
Refactor the finalization (compute res from d, final_p, sign, etc.)
to run once after the optional-exponent block. The malformed-exponent
case now falls through using the mantissa-only `final_p = trunc - dp`,
producing the same result strtod gives for the same input ("5e" -> 5.0
with endp at 'e'). Float("5e") still raises because mrb_str_len_to_dbl
rejects trailing characters under badcheck.
Reported by OSS-Fuzz (MSan).
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
+11
-29
@@ -1466,7 +1466,10 @@ mrb_read_float(const char *str, char **endp, double *fp)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* exponent */
|
||||
/* exponent (optional). On malformed exponent ("5e", "5e+"), keep `a`
|
||||
pointing at the 'e' so the caller's *endp reflects where parsing
|
||||
stopped, and fall through using the mantissa-only result. */
|
||||
int final_p = trunc - dp;
|
||||
if ((*p | 32) == 'e') {
|
||||
int e = 0;
|
||||
int exp_sign = 1;
|
||||
@@ -1474,37 +1477,17 @@ mrb_read_float(const char *str, char **endp, double *fp)
|
||||
if (*p == '-') { exp_sign = -1; p++; }
|
||||
else if (*p == '+') p++;
|
||||
|
||||
if (!ISDIGIT(*p)) goto done;
|
||||
|
||||
while (ISDIGIT(*p)) {
|
||||
if (e < 10000) e = e * 10 + (*p - '0');
|
||||
p++;
|
||||
if (ISDIGIT(*p)) {
|
||||
while (ISDIGIT(*p)) {
|
||||
if (e < 10000) e = e * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
final_p += e * exp_sign;
|
||||
a = p;
|
||||
}
|
||||
|
||||
{
|
||||
int final_p = e * exp_sign + trunc - dp;
|
||||
double res;
|
||||
if (d == 0) {
|
||||
res = 0.0;
|
||||
}
|
||||
else if (final_p > 308) {
|
||||
res = HUGE_VAL;
|
||||
}
|
||||
else if (final_p < -342 - nd) {
|
||||
res = 0.0;
|
||||
}
|
||||
else {
|
||||
res = parse_decimal(d, final_p);
|
||||
}
|
||||
if (sign < 0) res = -res;
|
||||
*fp = res;
|
||||
}
|
||||
a = p;
|
||||
goto done;
|
||||
}
|
||||
|
||||
{
|
||||
int final_p = trunc - dp;
|
||||
double res;
|
||||
if (d == 0) {
|
||||
res = 0.0;
|
||||
@@ -1522,7 +1505,6 @@ mrb_read_float(const char *str, char **endp, double *fp)
|
||||
*fp = res;
|
||||
}
|
||||
|
||||
done:
|
||||
if (endp) *endp = (char*)a;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user