Skip to content

Commit 6463cf0

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

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
@@ -994,6 +994,24 @@ def test_compat_unpickle(self):
994994
self.assertIs(type(unpickled), collections.UserDict)
995995
self.assertEqual(unpickled, collections.UserDict({1: 2}))
996996

997+
def test_bad_reduce(self):
998+
self.assertEqual(self.loads(b'cbuiltins\nint\n)R.'), 0)
999+
self.check_unpickling_error(TypeError, b'N)R.')
1000+
self.check_unpickling_error(TypeError, b'cbuiltins\nint\nNR.')
1001+
1002+
def test_bad_newobj(self):
1003+
error = (pickle.UnpicklingError, TypeError)
1004+
self.assertEqual(self.loads(b'cbuiltins\nint\n)\x81.'), 0)
1005+
self.check_unpickling_error(error, b'cbuiltins\nlen\n)\x81.')
1006+
self.check_unpickling_error(error, b'cbuiltins\nint\nN\x81.')
1007+
1008+
def test_bad_newobj_ex(self):
1009+
error = (pickle.UnpicklingError, TypeError)
1010+
self.assertEqual(self.loads(b'cbuiltins\nint\n)}\x92.'), 0)
1011+
self.check_unpickling_error(error, b'cbuiltins\nlen\n)}\x92.')
1012+
self.check_unpickling_error(error, b'cbuiltins\nint\nN}\x92.')
1013+
self.check_unpickling_error(error, b'cbuiltins\nint\n)N\x92.')
1014+
9971015
def test_bad_stack(self):
9981016
badpickles = [
9991017
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
@@ -5423,23 +5423,30 @@ load_newobj_ex(UnpicklerObject *self)
54235423
}
54245424

54255425
if (!PyType_Check(cls)) {
5426-
Py_DECREF(kwargs);
5427-
Py_DECREF(args);
54285426
PyErr_Format(st->UnpicklingError,
54295427
"NEWOBJ_EX class argument must be a type, not %.200s",
54305428
Py_TYPE(cls)->tp_name);
5431-
Py_DECREF(cls);
5432-
return -1;
5429+
goto error;
54335430
}
54345431

54355432
if (((PyTypeObject *)cls)->tp_new == NULL) {
5436-
Py_DECREF(kwargs);
5437-
Py_DECREF(args);
5438-
Py_DECREF(cls);
54395433
PyErr_SetString(st->UnpicklingError,
54405434
"NEWOBJ_EX class argument doesn't have __new__");
5441-
return -1;
5435+
goto error;
5436+
}
5437+
if (!PyTuple_Check(args)) {
5438+
PyErr_Format(st->UnpicklingError,
5439+
"NEWOBJ_EX args argument must be a tuple, not %.200s",
5440+
Py_TYPE(args)->tp_name);
5441+
goto error;
5442+
}
5443+
if (!PyDict_Check(kwargs)) {
5444+
PyErr_Format(st->UnpicklingError,
5445+
"NEWOBJ_EX kwargs argument must be a dict, not %.200s",
5446+
Py_TYPE(kwargs)->tp_name);
5447+
goto error;
54425448
}
5449+
54435450
obj = ((PyTypeObject *)cls)->tp_new((PyTypeObject *)cls, args, kwargs);
54445451
Py_DECREF(kwargs);
54455452
Py_DECREF(args);
@@ -5449,6 +5456,12 @@ load_newobj_ex(UnpicklerObject *self)
54495456
}
54505457
PDATA_PUSH(self->stack, obj, -1);
54515458
return 0;
5459+
5460+
error:
5461+
Py_DECREF(kwargs);
5462+
Py_DECREF(args);
5463+
Py_DECREF(cls);
5464+
return -1;
54525465
}
54535466

54545467
static int

0 commit comments

Comments
 (0)