summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--mrbgems/mruby-sprintf/src/sprintf.c38
-rw-r--r--mrbgems/mruby-sprintf/test/sprintf.rb1
-rw-r--r--src/numeric.c26
-rw-r--r--test/t/integer.rb3
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