ruby-changes:28156
From: akr <ko1@a...>
Date: Tue, 9 Apr 2013 20:40:08 +0900 (JST)
Subject: [ruby-changes:28156] akr:r40208 (trunk): * internal.h (MUL_OVERFLOW_SIGNED_INTEGER_P): New macro.
akr 2013-04-09 20:39:53 +0900 (Tue, 09 Apr 2013) New Revision: 40208 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=40208 Log: * 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. Modified files: trunk/ChangeLog trunk/array.c trunk/bignum.c trunk/insns.def trunk/internal.h trunk/numeric.c trunk/rational.c trunk/thread.c Index: array.c =================================================================== --- array.c (revision 40207) +++ array.c (revision 40208) @@ -5034,15 +5034,14 @@ rb_ary_product(int argc, VALUE *argv, VA https://github.com/ruby/ruby/blob/trunk/array.c#L5034 else { /* Compute the length of the result array; return [] if any is empty */ for (i = 0; i < n; i++) { - long k = RARRAY_LEN(arrays[i]), l = resultlen; + long k = RARRAY_LEN(arrays[i]); if (k == 0) { result = rb_ary_new2(0); goto done; } - resultlen *= k; - if (resultlen < k || resultlen < l || resultlen / k != l) { + if (MUL_OVERFLOW_LONG_P(resultlen, k)) rb_raise(rb_eRangeError, "too big to product"); - } + resultlen *= k; } result = rb_ary_new2(resultlen); } Index: ChangeLog =================================================================== --- ChangeLog (revision 40207) +++ ChangeLog (revision 40208) @@ -1,3 +1,27 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Tue Apr 9 20:38:20 2013 Tanaka Akira <akr@f...> + + * 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@f...> * lib/open-uri.rb: Support multiple fields with same field Index: insns.def =================================================================== --- insns.def (revision 40207) +++ insns.def (revision 40208) @@ -1418,16 +1418,13 @@ opt_mult https://github.com/ruby/ruby/blob/trunk/insns.def#L1418 val = recv; } else { - volatile long c; b = FIX2LONG(obj); - c = a * b; - - if (FIXABLE(c) && c / a == b) { - val = LONG2FIX(c); - } - else { + if (MUL_OVERFLOW_FIXNUM_P(a, b)) { val = rb_big_mul(rb_int2big(a), rb_int2big(b)); - } + } + else { + val = LONG2FIX(a * b); + } } } else if (FLONUM_2_P(recv, obj) && Index: thread.c =================================================================== --- thread.c (revision 40207) +++ thread.c (revision 40208) @@ -994,10 +994,17 @@ sleep_timeval(rb_thread_t *th, struct ti https://github.com/ruby/ruby/blob/trunk/thread.c#L994 enum rb_thread_status prev_status = th->status; 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) { - to.tv_sec++; - to.tv_usec -= 1000000; + if (to.tv_sec == TIMET_MAX) + to.tv_usec = 999999; + else { + to.tv_sec++; + to.tv_usec -= 1000000; + } } th->status = THREAD_STOPPED; Index: numeric.c =================================================================== --- numeric.c (revision 40207) +++ numeric.c (revision 40208) @@ -2731,7 +2731,6 @@ fix_mul(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L2731 #if SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG LONG_LONG d; #else - volatile long c; VALUE r; #endif @@ -2745,13 +2744,11 @@ fix_mul(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L2744 #else if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b)) return LONG2FIX(a*b); - c = a * b; - r = LONG2FIX(c); - 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)); - } + else + r = LONG2FIX(a * b); return r; #endif } @@ -2973,11 +2970,10 @@ int_pow(long x, unsigned long y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L2970 y >>= 1; } { - volatile long xz = x * z; - if (!POSFIXABLE(xz) || xz / x != z) { + if (MUL_OVERFLOW_FIXNUM_P(x, z)) { goto bignum; } - z = xz; + z = x * z; } } while (--y); if (neg) z = -z; Index: internal.h =================================================================== --- internal.h (revision 40207) +++ internal.h (revision 40208) @@ -28,6 +28,15 @@ extern "C" { https://github.com/ruby/ruby/blob/trunk/internal.h#L28 #endif #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 { char conflict[sizeof(VALUE) * 3]; }; Index: bignum.c =================================================================== --- bignum.c (revision 40207) +++ bignum.c (revision 40208) @@ -309,13 +309,17 @@ VALUE https://github.com/ruby/ruby/blob/trunk/bignum.c#L309 rb_int2big(SIGNED_VALUE n) { long neg = 0; + VALUE u; VALUE big; if (n < 0) { - n = -n; + u = 1 + (VALUE)(-(n + 1)); /* u = -n avoiding overflow */ neg = 1; } - big = rb_uint2big(n); + else { + u = n; + } + big = rb_uint2big(u); if (neg) { RBIGNUM_SET_SIGN(big, 0); } @@ -1224,12 +1228,15 @@ rb_big2ulong(VALUE x) https://github.com/ruby/ruby/blob/trunk/bignum.c#L1228 { VALUE num = big2ulong(x, "unsigned long", TRUE); - if (!RBIGNUM_SIGN(x)) { - unsigned long v = (unsigned long)(-(long)num); - - if (v <= LONG_MAX) - rb_raise(rb_eRangeError, "bignum out of range of unsigned long"); - return (VALUE)v; + if (RBIGNUM_POSITIVE_P(x)) { + 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 out of range of unsigned long"); } return num; } @@ -1239,12 +1246,18 @@ rb_big2long(VALUE x) https://github.com/ruby/ruby/blob/trunk/bignum.c#L1246 { VALUE num = big2ulong(x, "long", TRUE); - if ((long)num < 0 && - (RBIGNUM_SIGN(x) || (long)num != LONG_MIN)) { - rb_raise(rb_eRangeError, "bignum too big to convert into `long'"); + if (RBIGNUM_POSITIVE_P(x)) { + if (LONG_MAX < num) + 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 @@ -1272,13 +1285,15 @@ rb_big2ull(VALUE x) https://github.com/ruby/ruby/blob/trunk/bignum.c#L1285 { unsigned LONG_LONG num = big2ull(x, "unsigned long long"); - if (!RBIGNUM_SIGN(x)) { - LONG_LONG v = -(LONG_LONG)num; - - /* FIXNUM_MIN-1 .. LLONG_MIN mapped into 0xbfffffffffffffff .. LONG_MAX+1 */ - if ((unsigned LONG_LONG)v <= LLONG_MAX) - rb_raise(rb_eRangeError, "bignum out of range of unsigned long long"); - return v; + if (RBIGNUM_POSITIVE_P(x)) { + 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 out of range of unsigned long long"); } return num; } @@ -1288,12 +1303,18 @@ rb_big2ll(VALUE x) https://github.com/ruby/ruby/blob/trunk/bignum.c#L1303 { unsigned LONG_LONG num = big2ull(x, "long long"); - if ((LONG_LONG)num < 0 && (RBIGNUM_SIGN(x) - || (LONG_LONG)num != LLONG_MIN)) { - rb_raise(rb_eRangeError, "bignum too big to convert into `long long'"); + if (RBIGNUM_POSITIVE_P(x)) { + if (LLONG_MAX < num) + 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 */ Index: rational.c =================================================================== --- rational.c (revision 40207) +++ rational.c (revision 40208) @@ -639,7 +639,6 @@ inline static VALUE https://github.com/ruby/ruby/blob/trunk/rational.c#L639 f_imul(long a, long b) { VALUE r; - volatile long c; if (a == 0 || b == 0) return ZERO; @@ -648,10 +647,10 @@ f_imul(long a, long b) https://github.com/ruby/ruby/blob/trunk/rational.c#L647 else if (b == 1) return LONG2NUM(a); - c = a * b; - r = LONG2NUM(c); - if (NUM2LONG(r) != c || (c / a) != b) + if (MUL_OVERFLOW_LONG_P(a, b)) r = rb_big_mul(rb_int2big(a), rb_int2big(b)); + else + r = LONG2NUM(a * b); return r; } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/