Skip to content

Commit 620e276

Browse files
bpo-41288: Fix a crash in unpickling invalid NEWOBJ_EX. (GH-21458) (GH-21461)
Automerge-Triggered-By: @tiran (cherry picked from commit 4f309ab) Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent c8c818b commit 620e276

File tree

3 files changed

+41
-8
lines changed

3 files changed

+41
-8
lines changed

Lib/test/pickletester.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,24 @@ def test_compat_unpickle(self):
998998
self.assertIs(type(unpickled), collections.UserDict)
999999
self.assertEqual(unpickled, collections.UserDict({1: 2}))
10001000

1001+
def test_bad_reduce(self):
1002+
self.assertEqual(self.loads(b'cbuiltins\nint\n)R.'), 0)
1003+
self.check_unpickling_error(TypeError, b'N)R.')
1004+
self.check_unpickling_error(TypeError, b'cbuiltins\nint\nNR.')
1005+
1006+
def test_bad_newobj(self):
1007+
error = (pickle.UnpicklingError, TypeError)
1008+
self.assertEqual(self.loads(b'cbuiltins\nint\n)\x81.'), 0)
1009+
self.check_unpickling_error(error, b'cbuiltins\nlen\n)\x81.')
1010+
self.check_unpickling_error(error, b'cbuiltins\nint\nN\x81.')
1011+
1012+
def test_bad_newobj_ex(self):
1013+
error = (pickle.UnpicklingError, TypeError)
1014+
self.assertEqual(self.loads(b'cbuiltins\nint\n)}\x92.'), 0)
1015+
self.check_unpickling_error(error, b'cbuiltins\nlen\n)}\x92.')
1016+
self.check_unpickling_error(error, b'cbuiltins\nint\nN}\x92.')
1017+
self.check_unpickling_error(error, b'cbuiltins\nint\n)N\x92.')
1018+
10011019
def test_bad_stack(self):
10021020
badpickles = [
10031021
b'.', # STOP
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Unpickling invalid NEWOBJ_EX opcode with the C implementation raises now
2+
UnpicklingError instead of crashing.

Modules/_pickle.c

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5515,23 +5515,30 @@ load_newobj_ex(UnpicklerObject *self)
55155515
}
55165516

55175517
if (!PyType_Check(cls)) {
5518-
Py_DECREF(kwargs);
5519-
Py_DECREF(args);
55205518
PyErr_Format(st->UnpicklingError,
55215519
"NEWOBJ_EX class argument must be a type, not %.200s",
55225520
Py_TYPE(cls)->tp_name);
5523-
Py_DECREF(cls);
5524-
return -1;
5521+
goto error;
55255522
}
55265523

55275524
if (((PyTypeObject *)cls)->tp_new == NULL) {
5528-
Py_DECREF(kwargs);
5529-
Py_DECREF(args);
5530-
Py_DECREF(cls);
55315525
PyErr_SetString(st->UnpicklingError,
55325526
"NEWOBJ_EX class argument doesn't have __new__");
5533-
return -1;
5527+
goto error;
5528+
}
5529+
if (!PyTuple_Check(args)) {
5530+
PyErr_Format(st->UnpicklingError,
5531+
"NEWOBJ_EX args argument must be a tuple, not %.200s",
5532+
Py_TYPE(args)->tp_name);
5533+
goto error;
5534+
}
5535+
if (!PyDict_Check(kwargs)) {
5536+
PyErr_Format(st->UnpicklingError,
5537+
"NEWOBJ_EX kwargs argument must be a dict, not %.200s",
5538+
Py_TYPE(kwargs)->tp_name);
5539+
goto error;
55345540
}
5541+
55355542
obj = ((PyTypeObject *)cls)->tp_new((PyTypeObject *)cls, args, kwargs);
55365543
Py_DECREF(kwargs);
55375544
Py_DECREF(args);
@@ -5541,6 +5548,12 @@ load_newobj_ex(UnpicklerObject *self)
55415548
}
55425549
PDATA_PUSH(self->stack, obj, -1);
55435550
return 0;
5551+
5552+
error:
5553+
Py_DECREF(kwargs);
5554+
Py_DECREF(args);
5555+
Py_DECREF(cls);
5556+
return -1;
55445557
}
55455558

55465559
static int

0 commit comments

Comments
 (0)