ruby-changes:29442
From: akr <ko1@a...>
Date: Thu, 20 Jun 2013 22:05:50 +0900 (JST)
Subject: [ruby-changes:29442] akr:r41494 (trunk): * bignum.c (bary_unpack_internal): Return -2 when negative overflow.
akr 2013-06-20 22:05:27 +0900 (Thu, 20 Jun 2013) New Revision: 41494 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=41494 Log: * bignum.c (bary_unpack_internal): Return -2 when negative overflow. (bary_unpack): Set the overflowed bit if an extra BDIGIT exists. (rb_integer_unpack): Set the overflowed bit. Modified files: trunk/ChangeLog trunk/bignum.c trunk/test/-ext-/bignum/test_pack.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 41493) +++ ChangeLog (revision 41494) @@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Thu Jun 20 22:02:46 2013 Tanaka Akira <akr@f...> + + * bignum.c (bary_unpack_internal): Return -2 when negative overflow. + (bary_unpack): Set the overflowed bit if an extra BDIGIT exists. + (rb_integer_unpack): Set the overflowed bit. + Thu Jun 20 21:17:19 2013 Koichi Sasada <ko1@a...> * gc.c (rgengc_rememberset_mark): record Index: bignum.c =================================================================== --- bignum.c (revision 41493) +++ bignum.c (revision 41494) @@ -1259,26 +1259,26 @@ integer_unpack_push_bits(int data, int n https://github.com/ruby/ruby/blob/trunk/bignum.c#L1259 static int bary_unpack_internal(BDIGIT *bdigits, size_t num_bdigits, const void *words, size_t numwords, size_t wordsize, size_t nails, int flags, int nlp_bits) { - int sign = (flags & INTEGER_PACK_NEGATIVE) ? -1 : 1; - - const unsigned char *buf = words; + int sign; - BDIGIT *dp; - BDIGIT *de; + if (num_bdigits != 0) { + const unsigned char *buf = words; - int word_num_partialbits; - size_t word_num_fullbytes; + BDIGIT *dp; + BDIGIT *de; - ssize_t word_step; - size_t byte_start; - int byte_step; + int word_num_partialbits; + size_t word_num_fullbytes; - size_t word_start, word_last; - const unsigned char *wordp, *last_wordp; - BDIGIT_DBL dd; - int numbits_in_dd; + ssize_t word_step; + size_t byte_start; + int byte_step; + + size_t word_start, word_last; + const unsigned char *wordp, *last_wordp; + BDIGIT_DBL dd; + int numbits_in_dd; - if (num_bdigits) { dp = bdigits; de = dp + num_bdigits; @@ -1322,20 +1322,34 @@ bary_unpack_internal(BDIGIT *bdigits, si https://github.com/ruby/ruby/blob/trunk/bignum.c#L1322 #undef PUSH_BITS } - if (flags & INTEGER_PACK_2COMP) { - if (num_bdigits == 0) { - if (flags & INTEGER_PACK_NEGATIVE) + if (!(flags & INTEGER_PACK_2COMP)) { + sign = (flags & INTEGER_PACK_NEGATIVE) ? -1 : 1; + } + else { + if (nlp_bits) { + if ((flags & INTEGER_PACK_NEGATIVE) || + (bdigits[num_bdigits-1] >> (BITSPERDIG - nlp_bits - 1))) { + bdigits[num_bdigits-1] |= (~(BDIGIT)0) << (BITSPERDIG - nlp_bits); sign = -1; - else - sign = 0; + } + else { + sign = 1; + } } - else if ((flags & INTEGER_PACK_NEGATIVE) || - (num_bdigits != 0 && - (bdigits[num_bdigits-1] >> (BITSPERDIG - nlp_bits - 1)))) { - if (nlp_bits) - bdigits[num_bdigits-1] |= (~(BDIGIT)0) << (BITSPERDIG - nlp_bits); + else { + if (flags & INTEGER_PACK_NEGATIVE) { + sign = bary_zero_p(bdigits, num_bdigits) ? -2 : -1; + } + else { + if (num_bdigits != 0 && + (bdigits[num_bdigits-1] >> (BITSPERDIG - 1))) + sign = -1; + else + sign = 1; + } + } + if (sign == -1 && num_bdigits != 0) { bary_2comp(bdigits, num_bdigits); - sign = -1; } } @@ -1347,6 +1361,7 @@ bary_unpack(BDIGIT *bdigits, size_t num_ https://github.com/ruby/ruby/blob/trunk/bignum.c#L1361 { size_t num_bdigits0; int nlp_bits; + int sign; validate_integer_pack_format(numwords, wordsize, nails, flags, INTEGER_PACK_MSWORD_FIRST| @@ -1362,7 +1377,14 @@ bary_unpack(BDIGIT *bdigits, size_t num_ https://github.com/ruby/ruby/blob/trunk/bignum.c#L1377 assert(num_bdigits0 <= num_bdigits); - bary_unpack_internal(bdigits, num_bdigits, words, numwords, wordsize, nails, flags, nlp_bits); + sign = bary_unpack_internal(bdigits, num_bdigits0, words, numwords, wordsize, nails, flags, nlp_bits); + + if (num_bdigits0 < num_bdigits) { + MEMZERO(bdigits + num_bdigits0, BDIGIT, num_bdigits - num_bdigits0); + if (sign == -2) { + bdigits[num_bdigits0] = 1; + } + } } /* @@ -1429,16 +1451,19 @@ rb_integer_unpack(const void *words, siz https://github.com/ruby/ruby/blob/trunk/bignum.c#L1451 num_bdigits = integer_unpack_num_bdigits(numwords, wordsize, nails, &nlp_bits); - if (LONG_MAX < num_bdigits) + if (LONG_MAX-1 < num_bdigits) rb_raise(rb_eArgError, "too big to unpack as an integer"); val = bignew((long)num_bdigits, 0); ds = BDIGITS(val); sign = bary_unpack_internal(ds, num_bdigits, words, numwords, wordsize, nails, flags, nlp_bits); - if ((flags & INTEGER_PACK_2COMP) && num_bdigits == 0 && sign < 0) { - rb_big_resize(val, 1); - ds[0] = 1; + if (sign == -2) { + rb_big_resize(val, (long)num_bdigits+1); + BDIGITS(val)[num_bdigits] = 1; } + if ((flags & INTEGER_PACK_FORCE_BIGNUM) && sign != 0 && + bary_zero_p(BDIGITS(val), RBIGNUM_LEN(val))) + sign = 0; RBIGNUM_SET_SIGN(val, 0 <= sign); if (flags & INTEGER_PACK_FORCE_BIGNUM) Index: test/-ext-/bignum/test_pack.rb =================================================================== --- test/-ext-/bignum/test_pack.rb (revision 41493) +++ test/-ext-/bignum/test_pack.rb (revision 41494) @@ -194,5 +194,10 @@ class TestBignum < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/-ext-/bignum/test_pack.rb#L194 assert_equal( -1, Integer.test_unpack("\xFF", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) end + def test_unpack2comp_negative_zero + 0.upto(100) {|n| + assert_equal(-(256**n), Integer.test_unpack("\x00"*n, n, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) + } + end end end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/