[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]