Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4471400

Browse files
committed
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.
1 parent d8ae7c2 commit 4471400

2 files changed

Lines changed: 19 additions & 12 deletions

File tree

Lib/pickle.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -243,18 +243,25 @@ def save_none(self, object):
243243

244244
def save_int(self, object):
245245
if self.bin:
246-
i = mdumps(object)[1:]
247-
if i[-2:] == '\000\000':
248-
if i[-3] == '\000':
249-
self.write(BININT1 + i[:-3])
250-
return
251-
252-
self.write(BININT2 + i[:-2])
246+
# If the int is small enough to fit in a signed 4-byte 2's-comp
247+
# format, we can store it more efficiently than the general
248+
# case.
249+
high_bits = object >> 31 # note that Python shift sign-extends
250+
if high_bits == 0 or high_bits == -1:
251+
# All high bits are copies of bit 2**31, so the value
252+
# fits in a 4-byte signed int.
253+
i = mdumps(object)[1:]
254+
assert len(i) == 4
255+
if i[-2:] == '\000\000': # fits in 2-byte unsigned int
256+
if i[-3] == '\000': # fits in 1-byte unsigned int
257+
self.write(BININT1 + i[0])
258+
else:
259+
self.write(BININT2 + i[:2])
260+
else:
261+
self.write(BININT + i)
253262
return
254-
255-
self.write(BININT + i)
256-
else:
257-
self.write(INT + `object` + '\n')
263+
# Text pickle, or int too big to fit in signed 4-byte format.
264+
self.write(INT + `object` + '\n')
258265
dispatch[IntType] = save_int
259266

260267
def save_long(self, object):

Python/marshal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ w_object(PyObject *v, WFILE *p)
126126
else if (PyInt_Check(v)) {
127127
long x = PyInt_AS_LONG((PyIntObject *)v);
128128
#if SIZEOF_LONG > 4
129-
long y = x>>31;
129+
long y = Py_ARITHMETIC_RIGHT_SHIFT(long, x, 31);
130130
if (y && y != -1) {
131131
w_byte(TYPE_INT64, p);
132132
w_long64(x, p);

0 commit comments

Comments
 (0)