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

Skip to content

Commit 9982c53

Browse files
committed
Issue #12848: The pure Python pickle implementation now treats object lengths as unsigned 32-bit integers, like the C implementation does.
Patch by Serhiy Storchaka.
2 parents 9ab09d1 + bf6ecf9 commit 9982c53

3 files changed

Lines changed: 31 additions & 14 deletions

File tree

Lib/pickle.py

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ def put(self, i, pack=struct.pack):
263263
if i < 256:
264264
return BINPUT + bytes([i])
265265
else:
266-
return LONG_BINPUT + pack("<i", i)
266+
return LONG_BINPUT + pack("<I", i)
267267

268268
return PUT + repr(i).encode("ascii") + b'\n'
269269

@@ -273,7 +273,7 @@ def get(self, i, pack=struct.pack):
273273
if i < 256:
274274
return BINGET + bytes([i])
275275
else:
276-
return LONG_BINGET + pack("<i", i)
276+
return LONG_BINGET + pack("<I", i)
277277

278278
return GET + repr(i).encode("ascii") + b'\n'
279279

@@ -503,15 +503,15 @@ def save_bytes(self, obj, pack=struct.pack):
503503
if n < 256:
504504
self.write(SHORT_BINBYTES + bytes([n]) + bytes(obj))
505505
else:
506-
self.write(BINBYTES + pack("<i", n) + bytes(obj))
506+
self.write(BINBYTES + pack("<I", n) + bytes(obj))
507507
self.memoize(obj)
508508
dispatch[bytes] = save_bytes
509509

510510
def save_str(self, obj, pack=struct.pack):
511511
if self.bin:
512512
encoded = obj.encode('utf-8', 'surrogatepass')
513513
n = len(encoded)
514-
self.write(BINUNICODE + pack("<i", n) + encoded)
514+
self.write(BINUNICODE + pack("<I", n) + encoded)
515515
else:
516516
obj = obj.replace("\\", "\\u005c")
517517
obj = obj.replace("\n", "\\u000a")
@@ -931,6 +931,9 @@ def load_long1(self):
931931

932932
def load_long4(self):
933933
n = mloads(b'i' + self.read(4))
934+
if n < 0:
935+
# Corrupt or hostile pickle -- we never write one like this
936+
raise UnpicklingError("LONG pickle has negative byte count");
934937
data = self.read(n)
935938
self.append(decode_long(data))
936939
dispatch[LONG4[0]] = load_long4
@@ -959,23 +962,30 @@ def load_string(self):
959962
dispatch[STRING[0]] = load_string
960963

961964
def load_binstring(self):
965+
# Deprecated BINSTRING uses signed 32-bit length
962966
len = mloads(b'i' + self.read(4))
967+
if len < 0:
968+
raise UnpicklingError("BINSTRING pickle has negative byte count");
963969
data = self.read(len)
964970
value = str(data, self.encoding, self.errors)
965971
self.append(value)
966972
dispatch[BINSTRING[0]] = load_binstring
967973

968-
def load_binbytes(self):
969-
len = mloads(b'i' + self.read(4))
974+
def load_binbytes(self, unpack=struct.unpack, maxsize=sys.maxsize):
975+
len, = unpack('<I', self.read(4))
976+
if len > maxsize:
977+
raise UnpicklingError("BINBYTES exceeds system's maximum size of %d bytes" % maxsize);
970978
self.append(self.read(len))
971979
dispatch[BINBYTES[0]] = load_binbytes
972980

973981
def load_unicode(self):
974982
self.append(str(self.readline()[:-1], 'raw-unicode-escape'))
975983
dispatch[UNICODE[0]] = load_unicode
976984

977-
def load_binunicode(self):
978-
len = mloads(b'i' + self.read(4))
985+
def load_binunicode(self, unpack=struct.unpack, maxsize=sys.maxsize):
986+
len, = unpack('<I', self.read(4))
987+
if len > maxsize:
988+
raise UnpicklingError("BINUNICODE exceeds system's maximum size of %d bytes" % maxsize);
979989
self.append(str(self.read(len), 'utf-8', 'surrogatepass'))
980990
dispatch[BINUNICODE[0]] = load_binunicode
981991

@@ -1106,6 +1116,9 @@ def get_extension(self, code):
11061116
return
11071117
key = _inverted_registry.get(code)
11081118
if not key:
1119+
if code <= 0: # note that 0 is forbidden
1120+
# Corrupt or hostile pickle.
1121+
raise UnpicklingError("EXT specifies code <= 0");
11091122
raise ValueError("unregistered extension code %d" % code)
11101123
obj = self.find_class(*key)
11111124
_extension_cache[code] = obj
@@ -1159,8 +1172,8 @@ def load_binget(self):
11591172
self.append(self.memo[i])
11601173
dispatch[BINGET[0]] = load_binget
11611174

1162-
def load_long_binget(self):
1163-
i = mloads(b'i' + self.read(4))
1175+
def load_long_binget(self, unpack=struct.unpack):
1176+
i, = unpack('<I', self.read(4))
11641177
self.append(self.memo[i])
11651178
dispatch[LONG_BINGET[0]] = load_long_binget
11661179

@@ -1178,9 +1191,9 @@ def load_binput(self):
11781191
self.memo[i] = self.stack[-1]
11791192
dispatch[BINPUT[0]] = load_binput
11801193

1181-
def load_long_binput(self):
1182-
i = mloads(b'i' + self.read(4))
1183-
if i < 0:
1194+
def load_long_binput(self, unpack=struct.unpack, maxsize=sys.maxsize):
1195+
i, = unpack('<I', self.read(4))
1196+
if i > maxsize:
11841197
raise ValueError("negative LONG_BINPUT argument")
11851198
self.memo[i] = self.stack[-1]
11861199
dispatch[LONG_BINPUT[0]] = load_long_binput

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ Core and Builtins
9494
Library
9595
-------
9696

97+
- Issue #12848: The pure Python pickle implementation now treats object
98+
lengths as unsigned 32-bit integers, like the C implementation does.
99+
Patch by Serhiy Storchaka.
100+
97101
- Issue #16408: Fix file descriptors not being closed in error conditions
98102
in the zipfile module. Patch by Serhiy Storchaka.
99103

Modules/_pickle.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1589,7 +1589,7 @@ save_long(PicklerObject *self, PyObject *obj)
15891589
* byte at the start, and cut it back later if possible.
15901590
*/
15911591
nbytes = (nbits >> 3) + 1;
1592-
if (nbytes > INT_MAX) {
1592+
if (nbytes > 0x7fffffffL) {
15931593
PyErr_SetString(PyExc_OverflowError,
15941594
"long too large to pickle");
15951595
goto error;

0 commit comments

Comments
 (0)