From 555035a349bb9d7659317dc65dc68ce6e2e6aaa7 Mon Sep 17 00:00:00 2001 From: nagachika Date: Tue, 7 May 2013 16:49:01 +0000 Subject: merge revision(s) 40208: [Backport #8380] * 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/branches/ruby_2_0_0@40602 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- bignum.c | 71 +++++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 25 deletions(-) (limited to 'bignum.c') diff --git a/bignum.c b/bignum.c index 54dd75cf89..97557165b7 100644 --- a/bignum.c +++ b/bignum.c @@ -309,13 +309,17 @@ VALUE 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); } @@ -1222,12 +1226,15 @@ rb_big2ulong(VALUE x) { 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; } @@ -1237,12 +1244,18 @@ rb_big2long(VALUE x) { 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 @@ -1270,13 +1283,15 @@ rb_big2ull(VALUE x) { 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; } @@ -1286,12 +1301,18 @@ rb_big2ll(VALUE x) { 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 */ -- cgit v1.2.3