Skip to content

Commit 6f03b23

Browse files
PCManticoremiss-islington
authored andcommitted
bpo-38876: Raise pickle.UnpicklingError when loading an item from memo for invalid input (GH-17335)
The previous code was raising a `KeyError` for both the Python and C implementation. This was caused by the specified index of an invalid input which did not exist in the memo structure, where the pickle stores what objects it has seen. The malformed input would have caused either a `BINGET` or `LONG_BINGET` load from the memo, leading to a `KeyError` as the determined index was bogus. https://bugs.python.org/issue38876 https://bugs.python.org/issue38876
1 parent e407646 commit 6f03b23

File tree

4 files changed

+35
-8
lines changed

4 files changed

+35
-8
lines changed

Lib/pickle.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -1604,17 +1604,29 @@ def load_dup(self):
16041604

16051605
def load_get(self):
16061606
i = int(self.readline()[:-1])
1607-
self.append(self.memo[i])
1607+
try:
1608+
self.append(self.memo[i])
1609+
except KeyError:
1610+
msg = f'Memo value not found at index {i}'
1611+
raise UnpicklingError(msg) from None
16081612
dispatch[GET[0]] = load_get
16091613

16101614
def load_binget(self):
16111615
i = self.read(1)[0]
1612-
self.append(self.memo[i])
1616+
try:
1617+
self.append(self.memo[i])
1618+
except KeyError as exc:
1619+
msg = f'Memo value not found at index {i}'
1620+
raise UnpicklingError(msg) from None
16131621
dispatch[BINGET[0]] = load_binget
16141622

16151623
def load_long_binget(self):
16161624
i, = unpack('<I', self.read(4))
1617-
self.append(self.memo[i])
1625+
try:
1626+
self.append(self.memo[i])
1627+
except KeyError as exc:
1628+
msg = f'Memo value not found at index {i}'
1629+
raise UnpicklingError(msg) from None
16181630
dispatch[LONG_BINGET[0]] = load_long_binget
16191631

16201632
def load_put(self):

Lib/test/pickletester.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,9 @@ def test_short_binunicode(self):
10191019
self.assertEqual(self.loads(dumped), '\u20ac\x00')
10201020

10211021
def test_misc_get(self):
1022-
self.check_unpickling_error(KeyError, b'g0\np0')
1022+
self.check_unpickling_error(pickle.UnpicklingError, b'g0\np0')
1023+
self.check_unpickling_error(pickle.UnpicklingError, b'jens:')
1024+
self.check_unpickling_error(pickle.UnpicklingError, b'hens:')
10231025
self.assert_is_copy([(100,), (100,)],
10241026
self.loads(b'((Kdtp0\nh\x00l.))'))
10251027

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Raise pickle.UnpicklingError when loading an item from memo for invalid
2+
input
3+
4+
The previous code was raising a `KeyError` for both the Python and C
5+
implementation. This was caused by the specified index of an invalid input
6+
which did not exist in the memo structure, where the pickle stores what
7+
objects it has seen. The malformed input would have caused either a `BINGET`
8+
or `LONG_BINGET` load from the memo, leading to a `KeyError` as the
9+
determined index was bogus. Patch by Claudiu Popa

Modules/_pickle.c

+8-4
Original file line numberDiff line numberDiff line change
@@ -6174,8 +6174,10 @@ load_get(UnpicklerObject *self)
61746174

61756175
value = _Unpickler_MemoGet(self, idx);
61766176
if (value == NULL) {
6177-
if (!PyErr_Occurred())
6178-
PyErr_SetObject(PyExc_KeyError, key);
6177+
if (!PyErr_Occurred()) {
6178+
PickleState *st = _Pickle_GetGlobalState();
6179+
PyErr_Format(st->UnpicklingError, "Memo value not found at index %ld", idx);
6180+
}
61796181
Py_DECREF(key);
61806182
return -1;
61816183
}
@@ -6201,7 +6203,8 @@ load_binget(UnpicklerObject *self)
62016203
if (value == NULL) {
62026204
PyObject *key = PyLong_FromSsize_t(idx);
62036205
if (key != NULL) {
6204-
PyErr_SetObject(PyExc_KeyError, key);
6206+
PickleState *st = _Pickle_GetGlobalState();
6207+
PyErr_Format(st->UnpicklingError, "Memo value not found at index %ld", idx);
62056208
Py_DECREF(key);
62066209
}
62076210
return -1;
@@ -6227,7 +6230,8 @@ load_long_binget(UnpicklerObject *self)
62276230
if (value == NULL) {
62286231
PyObject *key = PyLong_FromSsize_t(idx);
62296232
if (key != NULL) {
6230-
PyErr_SetObject(PyExc_KeyError, key);
6233+
PickleState *st = _Pickle_GetGlobalState();
6234+
PyErr_Format(st->UnpicklingError, "Memo value not found at index %ld", idx);
62316235
Py_DECREF(key);
62326236
}
62336237
return -1;

0 commit comments

Comments
 (0)