diff options
| -rw-r--r-- | mrbgems/mruby-sprintf/src/sprintf.c | 38 | ||||
| -rw-r--r-- | mrbgems/mruby-sprintf/test/sprintf.rb | 1 | ||||
| -rw-r--r-- | src/numeric.c | 26 | ||||
| -rw-r--r-- | test/t/integer.rb | 3 |
4 files changed, 44 insertions, 24 deletions
diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 81b48b10d..0a964801e 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -71,7 +71,7 @@ sign_bits(int base, const char *p) static mrb_value mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base) { - char buf[64], *b = buf + sizeof buf; + char buf[66], *b = buf + sizeof buf; mrb_int num = mrb_fixnum(x); uint64_t val = (uint64_t)num; char d; @@ -79,10 +79,6 @@ mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base) if (base != 2) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base)); } - - if (val >= (1 << 10)) - val &= 0x3ff; - if (val == 0) { return mrb_str_new_lit(mrb, "0"); } @@ -763,11 +759,11 @@ retry: case 'B': case 'u': { mrb_value val = GETARG(); - char fbuf[32], nbuf[64], *s; + char fbuf[32], nbuf[68], *s; const char *prefix = NULL; int sign = 0, dots = 0; char sc = 0; - mrb_int v = 0, org_v = 0; + mrb_int v = 0; int base; mrb_int len; @@ -800,10 +796,6 @@ retry: bin_retry: switch (mrb_type(val)) { case MRB_TT_FLOAT: - if (FIXABLE(mrb_float(val))) { - val = mrb_fixnum_value((mrb_int)mrb_float(val)); - goto bin_retry; - } val = mrb_flo_to_fixnum(mrb, val); if (mrb_fixnum_p(val)) goto bin_retry; break; @@ -835,7 +827,6 @@ retry: } if (base == 2) { - org_v = v; if (v < 0 && !sign) { val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base); dots = 1; @@ -843,12 +834,10 @@ retry: else { val = mrb_fixnum_to_str(mrb, mrb_fixnum_value(v), base); } - v = mrb_fixnum(mrb_str_to_inum(mrb, val, 10, FALSE)); } if (sign) { char c = *p; if (c == 'i') c = 'd'; /* %d and %i are identical */ - if (base == 2) c = 'd'; if (v < 0) { v = -v; sc = '-'; @@ -862,20 +851,29 @@ retry: sc = ' '; width--; } - snprintf(fbuf, sizeof(fbuf), "%%l%c", c); - snprintf(nbuf, sizeof(nbuf), fbuf, v); + if (base == 2) { + snprintf(nbuf, sizeof(nbuf), "%s", RSTRING_PTR(val)); + } + else { + snprintf(fbuf, sizeof(fbuf), "%%l%c", c); + snprintf(nbuf, sizeof(nbuf), fbuf, v); + } s = nbuf; } else { char c = *p; if (c == 'X') c = 'x'; - if (base == 2) c = 'd'; s = nbuf; if (v < 0) { dots = 1; } - snprintf(fbuf, sizeof(fbuf), "%%l%c", c); - snprintf(++s, sizeof(nbuf) - 1, fbuf, v); + if (base == 2) { + snprintf(++s, sizeof(nbuf) - 1, "%s", RSTRING_PTR(val)); + } + else { + snprintf(fbuf, sizeof(fbuf), "%%l%c", c); + snprintf(++s, sizeof(nbuf) - 1, fbuf, v); + } if (v < 0) { char d; @@ -965,7 +963,7 @@ retry: CHECK(prec - len); if (dots) PUSH("..", 2); - if (v < 0 || (base == 2 && org_v < 0)) { + if (v < 0) { char c = sign_bits(base, p); while (len < prec--) { buf[blen++] = c; diff --git a/mrbgems/mruby-sprintf/test/sprintf.rb b/mrbgems/mruby-sprintf/test/sprintf.rb index 7007df1fa..454c226e1 100644 --- a/mrbgems/mruby-sprintf/test/sprintf.rb +++ b/mrbgems/mruby-sprintf/test/sprintf.rb @@ -5,4 +5,5 @@ assert('String#%') do assert_equal "one=1", "one=%d" % 1 assert_equal "1 one 1.0", "%d %s %3.1f" % [ 1, "one", 1.01 ] assert_equal "123 < 456", "%{num} < %<str>s" % { num: 123, str: "456" } + assert_equal 16, ("%b" % (1<<15)).size end diff --git a/src/numeric.c b/src/numeric.c index e64cd2d8d..bd90f6168 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -821,15 +821,28 @@ static mrb_value lshift(mrb_state *mrb, mrb_int val, mrb_int width) { mrb_assert(width > 0); - if ((width > NUMERIC_SHIFT_WIDTH_MAX) || - (val > (MRB_INT_MAX >> width))) { + if (val > 0) { + if ((width > NUMERIC_SHIFT_WIDTH_MAX) || + (val > (MRB_INT_MAX >> width))) { + goto bit_overflow; + } + } else { + if ((width > NUMERIC_SHIFT_WIDTH_MAX) || + (val < (MRB_INT_MIN >> width))) { + goto bit_overflow; + } + } + + return mrb_fixnum_value(val << width); + +bit_overflow: + { mrb_float f = (mrb_float)val; while (width--) { f *= 2; } return mrb_float_value(mrb, f); } - return mrb_fixnum_value(val << width); } static mrb_value @@ -951,7 +964,12 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) if (isnan(d)) { mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN"); } - z = (mrb_int)d; + if (FIXABLE(d)) { + z = (mrb_int)d; + } + else { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x); + } } return mrb_fixnum_value(z); } diff --git a/test/t/integer.rb b/test/t/integer.rb index c6084bfeb..5379744e5 100644 --- a/test/t/integer.rb +++ b/test/t/integer.rb @@ -150,6 +150,9 @@ assert('Integer#<<', '15.2.8.3.12') do # Left Shift by 31 is bitShift overflow to SignedInt assert_equal 2147483648, 1 << 31 + + # -3 Left Shift by 30 is bitShift overflow to SignedInt + assert_equal -3221225472, -3 << 30 end assert('Integer#>>', '15.2.8.3.13') do |
