summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2013-02-03 16:10:34 -0800
committerYukihiro "Matz" Matsumoto <[email protected]>2013-02-03 16:10:34 -0800
commit70eaa9d58e6141248b2e035379d2f4a3f96976a5 (patch)
treee80010eec27e979eb329de2ad84a10ccf8b17eab
parente887059cbf7e84e87525d9d330a0ce50da79f5e3 (diff)
parent641fc9902f6dd8c7b647a1bd61ee6fd9243acb34 (diff)
downloadmruby-70eaa9d58e6141248b2e035379d2f4a3f96976a5.tar.gz
mruby-70eaa9d58e6141248b2e035379d2f4a3f96976a5.zip
Merge pull request #815 from masamitsu-murase/modify_handling_of_large_fixnum
Modify handling of large fixnum
-rw-r--r--src/codegen.c60
-rw-r--r--src/numeric.c2
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;