diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen.c | 60 | ||||
| -rw-r--r-- | src/numeric.c | 2 |
2 files changed, 52 insertions, 10 deletions
diff --git a/src/codegen.c b/src/codegen.c index 5803a9c25..1f6d16477 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -959,6 +959,48 @@ readint_float(codegen_scope *s, const char *p, int base) return f; } +static mrb_int +readint_mrb_int(codegen_scope *s, const char *p, int base, int neg, int *overflow) +{ + const char *e = p + strlen(p); + mrb_int result = 0; + int n; + + if (*p == '+') p++; + while (p < e) { + char c = *p; + c = tolower((unsigned char)c); + for (n=0; n<base; n++) { + if (mrb_digitmap[n] == c) { + break; + } + } + if (n == base) { + codegen_error(s, "malformed readint input"); + } + + if (neg) { + if ((MRB_INT_MIN + n)/base > result) { + *overflow = TRUE; + return 0; + } + result *= base; + result -= n; + } + else { + if ((MRB_INT_MAX - n)/base < result) { + *overflow = TRUE; + return 0; + } + result *= base; + result += n; + } + p++; + } + *overflow = FALSE; + return result; +} + static void codegen(codegen_scope *s, node *tree, int val) { @@ -1733,18 +1775,18 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { char *p = (char*)tree->car; int base = (intptr_t)tree->cdr->car; - double f; mrb_int i; mrb_code co; + int overflow; - f = readint_float(s, p, base); - if (!FIXABLE(f)) { + i = readint_mrb_int(s, p, base, FALSE, &overflow); + if (overflow) { + double f = readint_float(s, p, base); int off = new_lit(s, mrb_float_value(f)); genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); } else { - i = (mrb_int)f; if (i < MAXARG_sBx && i > -MAXARG_sBx) { co = MKOP_AsBx(OP_LOADI, cursp(), i); } @@ -1789,18 +1831,18 @@ codegen(codegen_scope *s, node *tree, int val) { char *p = (char*)tree->car; int base = (intptr_t)tree->cdr->car; - mrb_float f; mrb_int i; mrb_code co; + int overflow; - f = readint_float(s, p, base); - if (!FIXABLE(f)) { + i = readint_mrb_int(s, p, base, TRUE, &overflow); + if (overflow) { + double f = readint_float(s, p, base); int off = new_lit(s, mrb_float_value(-f)); - + genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); } else { - i = (mrb_int)-f; if (i < MAXARG_sBx && i > -MAXARG_sBx) { co = MKOP_AsBx(OP_LOADI, cursp(), i); } diff --git a/src/numeric.c b/src/numeric.c index 8bf2b3382..f6894a57b 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1160,7 +1160,7 @@ fix_minus(mrb_state *mrb, mrb_value self) mrb_value mrb_fix2str(mrb_state *mrb, mrb_value x, int base) { - char buf[64], *b = buf + sizeof buf; + char buf[sizeof(mrb_int)*CHAR_BIT+2], *b = buf + sizeof buf; mrb_int val = mrb_fixnum(x); int neg = 0; |
