test_pickle works on sizeof(long)==8 boxes again.
authorTim Peters <tim.peters@gmail.com>
Tue, 10 Apr 2001 05:02:52 +0000 (05:02 +0000)
committerTim Peters <tim.peters@gmail.com>
Tue, 10 Apr 2001 05:02:52 +0000 (05:02 +0000)
pickle.py
    The code implicitly assumed that all ints fit in 4 bytes, causing all
    sorts of mischief (from nonsense results to corrupted pickles).
    Repaired that.
marshal.c
    The int marshaling code assumed that right shifts of signed longs
    sign-extend.  Repaired that.

Lib/pickle.py
Python/marshal.c

index 4abc046963eb02e19d23c08e5c8443cf2ee33814..f6cbea8f182a84a1c8439b4076fe673369398300 100644 (file)
@@ -243,18 +243,25 @@ class Pickler:
 
     def save_int(self, object):
         if self.bin:
-            i = mdumps(object)[1:]
-            if i[-2:] == '\000\000':
-                if i[-3] == '\000':
-                    self.write(BININT1 + i[:-3])
-                    return
-
-                self.write(BININT2 + i[:-2])
+            # If the int is small enough to fit in a signed 4-byte 2's-comp
+            # format, we can store it more efficiently than the general
+            # case.
+            high_bits = object >> 31  # note that Python shift sign-extends
+            if  high_bits == 0 or high_bits == -1:
+                # All high bits are copies of bit 2**31, so the value
+                # fits in a 4-byte signed int.
+                i = mdumps(object)[1:]
+                assert len(i) == 4
+                if i[-2:] == '\000\000':    # fits in 2-byte unsigned int
+                    if i[-3] == '\000':     # fits in 1-byte unsigned int
+                        self.write(BININT1 + i[0])
+                    else:
+                        self.write(BININT2 + i[:2])
+                else:
+                    self.write(BININT + i)
                 return
-
-            self.write(BININT + i)
-        else:
-            self.write(INT + `object` + '\n')
+        # Text pickle, or int too big to fit in signed 4-byte format.
+        self.write(INT + `object` + '\n')
     dispatch[IntType] = save_int
 
     def save_long(self, object):
index 1b9ab9af141d4b82ce52c1d5c64f8219f3ab8eed..120c3fade67a8f8dc2dce81edf6f8ee539319fcb 100644 (file)
@@ -126,7 +126,7 @@ w_object(PyObject *v, WFILE *p)
        else if (PyInt_Check(v)) {
                long x = PyInt_AS_LONG((PyIntObject *)v);
 #if SIZEOF_LONG > 4
-               long y = x>>31;
+               long y = Py_ARITHMETIC_RIGHT_SHIFT(long, x, 31);
                if (y && y != -1) {
                        w_byte(TYPE_INT64, p);
                        w_long64(x, p);