Fix buffer overflow in `mrb_str_len_to_dbl`.

Issue 19902: mruby:mruby_fuzzer: Stack-buffer-overflow in mrb_str_len_to_dbl
parent dbba0ca5
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#ifndef MRB_WITHOUT_FLOAT #ifndef MRB_WITHOUT_FLOAT
#include <float.h> #include <float.h>
#include <math.h>
#endif #endif
#include <limits.h> #include <limits.h>
#include <stddef.h> #include <stddef.h>
...@@ -2491,16 +2492,18 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self) ...@@ -2491,16 +2492,18 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self)
double double
mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck) mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck)
{ {
char buf[DBL_DIG * 4 + 10]; char buf[DBL_DIG * 4 + 20];
const char *p = s; const char *p = s, *p2;
const char *pend = p + len; const char *pend = p + len;
char *end; char *end;
char *n; char *n;
char prev = 0; char prev = 0;
double d; double d;
mrb_bool dot = FALSE;
if (!p) return 0.0; if (!p) return 0.0;
while (p<pend && ISSPACE(*p)) p++; while (p<pend && ISSPACE(*p)) p++;
p2 = p;
if (pend - p > 2 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { if (pend - p > 2 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
mrb_value x; mrb_value x;
...@@ -2515,21 +2518,27 @@ mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck) ...@@ -2515,21 +2518,27 @@ mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck)
} }
while (p < pend) { while (p < pend) {
if (!*p) { if (!*p) {
if (badcheck && p < pend) { if (badcheck) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte"); mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte");
/* not reached */ /* not reached */
} }
pend = p; pend = p;
p = s; p = p2;
goto nocopy;
}
if (!badcheck && *p == ' ') {
pend = p;
p = p2;
goto nocopy; goto nocopy;
} }
if (*p == '_') break; if (*p == '_') break;
p++; p++;
} }
p = s; p = p2;
n = buf; n = buf;
while (p < pend) { while (p < pend) {
char c = *p++; char c = *p++;
if (c == '.') dot = TRUE;
if (c == '_') { if (c == '_') {
/* remove an underscore between digits */ /* remove an underscore between digits */
if (n == buf || !ISDIGIT(prev) || p == pend) { if (n == buf || !ISDIGIT(prev) || p == pend) {
...@@ -2539,6 +2548,11 @@ mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck) ...@@ -2539,6 +2548,11 @@ mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck)
} }
else if (badcheck && prev == '_' && !ISDIGIT(c)) goto bad; else if (badcheck && prev == '_' && !ISDIGIT(c)) goto bad;
else { else {
const char *bend = buf+sizeof(buf)-1;
if (n==bend) { /* buffer overflow */
if (dot) break; /* cut off remaining fractions */
return INFINITY;
}
*n++ = c; *n++ = c;
} }
prev = c; prev = c;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment