From 44714007e888acba27d8527122bf618c28a4120b Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Tue, 10 Apr 2001 05:02:52 +0000 Subject: test_pickle works on sizeof(long)==8 boxes again. 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 | 29 ++++++++++++++++++----------- Python/marshal.c | 2 +- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Lib/pickle.py b/Lib/pickle.py index 4abc046..f6cbea8 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -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): diff --git a/Python/marshal.c b/Python/marshal.c index 1b9ab9a..120c3fa 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -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); -- cgit v0.12