* internal.h (MUL_OVERFLOW_SIGNED_INTEGER_P): New macro.

(MUL_OVERFLOW_FIXNUM_P): Ditto.
  (MUL_OVERFLOW_LONG_P): Ditto.

* array.c (rb_ary_product): Don't overflow on signed integer
  multiplication.

* numeric.c (fix_mul): Ditto.
  (int_pow): Ditto.

* rational.c (f_imul): Ditto.

* insns.def (opt_mult): Ditto.

* thread.c (sleep_timeval): Don't overflow on signed integer addition.

* bignum.c (rb_int2big): Don't overflow on signed integer negation.
  (rb_big2ulong): Ditto.
  (rb_big2long): Ditto.
  (rb_big2ull): Ditto.
  (rb_big2ll): Ditto.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40208 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2013-04-09 11:39:53 +00:00
parent 4329b14cfb
commit 712c7168bf
8 changed files with 105 additions and 53 deletions

View File

@ -1,3 +1,27 @@
Tue Apr 9 20:38:20 2013 Tanaka Akira <akr@fsij.org>
* internal.h (MUL_OVERFLOW_SIGNED_INTEGER_P): New macro.
(MUL_OVERFLOW_FIXNUM_P): Ditto.
(MUL_OVERFLOW_LONG_P): Ditto.
* array.c (rb_ary_product): Don't overflow on signed integer
multiplication.
* numeric.c (fix_mul): Ditto.
(int_pow): Ditto.
* rational.c (f_imul): Ditto.
* insns.def (opt_mult): Ditto.
* thread.c (sleep_timeval): Don't overflow on signed integer addition.
* bignum.c (rb_int2big): Don't overflow on signed integer negation.
(rb_big2ulong): Ditto.
(rb_big2long): Ditto.
(rb_big2ull): Ditto.
(rb_big2ll): Ditto.
Tue Apr 9 19:45:44 2013 Tanaka Akira <akr@fsij.org> Tue Apr 9 19:45:44 2013 Tanaka Akira <akr@fsij.org>
* lib/open-uri.rb: Support multiple fields with same field * lib/open-uri.rb: Support multiple fields with same field

View File

@ -5034,15 +5034,14 @@ rb_ary_product(int argc, VALUE *argv, VALUE ary)
else { else {
/* Compute the length of the result array; return [] if any is empty */ /* Compute the length of the result array; return [] if any is empty */
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
long k = RARRAY_LEN(arrays[i]), l = resultlen; long k = RARRAY_LEN(arrays[i]);
if (k == 0) { if (k == 0) {
result = rb_ary_new2(0); result = rb_ary_new2(0);
goto done; goto done;
} }
resultlen *= k; if (MUL_OVERFLOW_LONG_P(resultlen, k))
if (resultlen < k || resultlen < l || resultlen / k != l) {
rb_raise(rb_eRangeError, "too big to product"); rb_raise(rb_eRangeError, "too big to product");
} resultlen *= k;
} }
result = rb_ary_new2(resultlen); result = rb_ary_new2(resultlen);
} }

View File

@ -309,13 +309,17 @@ VALUE
rb_int2big(SIGNED_VALUE n) rb_int2big(SIGNED_VALUE n)
{ {
long neg = 0; long neg = 0;
VALUE u;
VALUE big; VALUE big;
if (n < 0) { if (n < 0) {
n = -n; u = 1 + (VALUE)(-(n + 1)); /* u = -n avoiding overflow */
neg = 1; neg = 1;
} }
big = rb_uint2big(n); else {
u = n;
}
big = rb_uint2big(u);
if (neg) { if (neg) {
RBIGNUM_SET_SIGN(big, 0); RBIGNUM_SET_SIGN(big, 0);
} }
@ -1224,12 +1228,15 @@ rb_big2ulong(VALUE x)
{ {
VALUE num = big2ulong(x, "unsigned long", TRUE); VALUE num = big2ulong(x, "unsigned long", TRUE);
if (!RBIGNUM_SIGN(x)) { if (RBIGNUM_POSITIVE_P(x)) {
unsigned long v = (unsigned long)(-(long)num); return num;
}
if (v <= LONG_MAX) else {
rb_raise(rb_eRangeError, "bignum out of range of unsigned long"); if (num <= LONG_MAX)
return (VALUE)v; return -(long)num;
if (num == 1+(unsigned long)(-(LONG_MIN+1)))
return LONG_MIN;
rb_raise(rb_eRangeError, "bignum out of range of unsigned long");
} }
return num; return num;
} }
@ -1239,12 +1246,18 @@ rb_big2long(VALUE x)
{ {
VALUE num = big2ulong(x, "long", TRUE); VALUE num = big2ulong(x, "long", TRUE);
if ((long)num < 0 && if (RBIGNUM_POSITIVE_P(x)) {
(RBIGNUM_SIGN(x) || (long)num != LONG_MIN)) { if (LONG_MAX < num)
rb_raise(rb_eRangeError, "bignum too big to convert into `long'"); rb_raise(rb_eRangeError, "bignum too big to convert into `long'");
return num;
}
else {
if (num <= LONG_MAX)
return -(long)num;
if (num == 1+(unsigned long)(-(LONG_MIN+1)))
return LONG_MIN;
rb_raise(rb_eRangeError, "bignum too big to convert into `long'");
} }
if (!RBIGNUM_SIGN(x)) return -(SIGNED_VALUE)num;
return num;
} }
#if HAVE_LONG_LONG #if HAVE_LONG_LONG
@ -1272,13 +1285,15 @@ rb_big2ull(VALUE x)
{ {
unsigned LONG_LONG num = big2ull(x, "unsigned long long"); unsigned LONG_LONG num = big2ull(x, "unsigned long long");
if (!RBIGNUM_SIGN(x)) { if (RBIGNUM_POSITIVE_P(x)) {
LONG_LONG v = -(LONG_LONG)num; return num;
}
/* FIXNUM_MIN-1 .. LLONG_MIN mapped into 0xbfffffffffffffff .. LONG_MAX+1 */ else {
if ((unsigned LONG_LONG)v <= LLONG_MAX) if (num <= LLONG_MAX)
rb_raise(rb_eRangeError, "bignum out of range of unsigned long long"); return -(LONG_LONG)num;
return v; if (num == 1+(unsigned LONG_LONG)(-(LLONG_MIN+1)))
return LLONG_MIN;
rb_raise(rb_eRangeError, "bignum out of range of unsigned long long");
} }
return num; return num;
} }
@ -1288,12 +1303,18 @@ rb_big2ll(VALUE x)
{ {
unsigned LONG_LONG num = big2ull(x, "long long"); unsigned LONG_LONG num = big2ull(x, "long long");
if ((LONG_LONG)num < 0 && (RBIGNUM_SIGN(x) if (RBIGNUM_POSITIVE_P(x)) {
|| (LONG_LONG)num != LLONG_MIN)) { if (LLONG_MAX < num)
rb_raise(rb_eRangeError, "bignum too big to convert into `long long'"); rb_raise(rb_eRangeError, "bignum too big to convert into `long long'");
return num;
}
else {
if (num <= LLONG_MAX)
return -(LONG_LONG)num;
if (num == 1+(unsigned LONG_LONG)(-(LLONG_MIN+1)))
return LLONG_MIN;
rb_raise(rb_eRangeError, "bignum too big to convert into `long long'");
} }
if (!RBIGNUM_SIGN(x)) return -(LONG_LONG)num;
return num;
} }
#endif /* HAVE_LONG_LONG */ #endif /* HAVE_LONG_LONG */

View File

@ -1418,16 +1418,13 @@ opt_mult
val = recv; val = recv;
} }
else { else {
volatile long c;
b = FIX2LONG(obj); b = FIX2LONG(obj);
c = a * b; if (MUL_OVERFLOW_FIXNUM_P(a, b)) {
if (FIXABLE(c) && c / a == b) {
val = LONG2FIX(c);
}
else {
val = rb_big_mul(rb_int2big(a), rb_int2big(b)); val = rb_big_mul(rb_int2big(a), rb_int2big(b));
} }
else {
val = LONG2FIX(a * b);
}
} }
} }
else if (FLONUM_2_P(recv, obj) && else if (FLONUM_2_P(recv, obj) &&

View File

@ -28,6 +28,15 @@ extern "C" {
#endif #endif
#define TIMET_MAX_PLUS_ONE (2*(double)(TIMET_MAX/2+1)) #define TIMET_MAX_PLUS_ONE (2*(double)(TIMET_MAX/2+1))
#define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
(a) == 0 ? 0 : \
(a) == -1 ? (b) < -(max) : \
(a) > 0 ? \
((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \
((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b)))
#define MUL_OVERFLOW_FIXNUM_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
#define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
struct rb_deprecated_classext_struct { struct rb_deprecated_classext_struct {
char conflict[sizeof(VALUE) * 3]; char conflict[sizeof(VALUE) * 3];
}; };

View File

@ -2731,7 +2731,6 @@ fix_mul(VALUE x, VALUE y)
#if SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG #if SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG
LONG_LONG d; LONG_LONG d;
#else #else
volatile long c;
VALUE r; VALUE r;
#endif #endif
@ -2745,13 +2744,11 @@ fix_mul(VALUE x, VALUE y)
#else #else
if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b)) if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b))
return LONG2FIX(a*b); return LONG2FIX(a*b);
c = a * b;
r = LONG2FIX(c);
if (a == 0) return x; if (a == 0) return x;
if (FIX2LONG(r) != c || c/a != b) { if (MUL_OVERFLOW_FIXNUM_P(a, b))
r = rb_big_mul(rb_int2big(a), rb_int2big(b)); r = rb_big_mul(rb_int2big(a), rb_int2big(b));
} else
r = LONG2FIX(a * b);
return r; return r;
#endif #endif
} }
@ -2973,11 +2970,10 @@ int_pow(long x, unsigned long y)
y >>= 1; y >>= 1;
} }
{ {
volatile long xz = x * z; if (MUL_OVERFLOW_FIXNUM_P(x, z)) {
if (!POSFIXABLE(xz) || xz / x != z) {
goto bignum; goto bignum;
} }
z = xz; z = x * z;
} }
} while (--y); } while (--y);
if (neg) z = -z; if (neg) z = -z;

View File

@ -639,7 +639,6 @@ inline static VALUE
f_imul(long a, long b) f_imul(long a, long b)
{ {
VALUE r; VALUE r;
volatile long c;
if (a == 0 || b == 0) if (a == 0 || b == 0)
return ZERO; return ZERO;
@ -648,10 +647,10 @@ f_imul(long a, long b)
else if (b == 1) else if (b == 1)
return LONG2NUM(a); return LONG2NUM(a);
c = a * b; if (MUL_OVERFLOW_LONG_P(a, b))
r = LONG2NUM(c);
if (NUM2LONG(r) != c || (c / a) != b)
r = rb_big_mul(rb_int2big(a), rb_int2big(b)); r = rb_big_mul(rb_int2big(a), rb_int2big(b));
else
r = LONG2NUM(a * b);
return r; return r;
} }

View File

@ -994,10 +994,17 @@ sleep_timeval(rb_thread_t *th, struct timeval tv, int spurious_check)
enum rb_thread_status prev_status = th->status; enum rb_thread_status prev_status = th->status;
getclockofday(&to); getclockofday(&to);
to.tv_sec += tv.tv_sec; if (TIMET_MAX - tv.tv_sec < to.tv_sec)
to.tv_sec = TIMET_MAX;
else
to.tv_sec += tv.tv_sec;
if ((to.tv_usec += tv.tv_usec) >= 1000000) { if ((to.tv_usec += tv.tv_usec) >= 1000000) {
to.tv_sec++; if (to.tv_sec == TIMET_MAX)
to.tv_usec -= 1000000; to.tv_usec = 999999;
else {
to.tv_sec++;
to.tv_usec -= 1000000;
}
} }
th->status = THREAD_STOPPED; th->status = THREAD_STOPPED;