1 From 620e276a8c1d53332fbf08d369be87f862b6949d Mon Sep 17 00:00:00 2001
2 From: "Miss Islington (bot)"
3 <31488909+miss-islington@users.noreply.github.com>
4 Date: Mon, 13 Jul 2020 11:17:01 -0700
5 Subject: [PATCH] bpo-41288: Fix a crash in unpickling invalid NEWOBJ_EX.
8 Automerge-Triggered-By: @tiran
9 (cherry picked from commit 4f309abf55f0e6f8950ac13d6ec83c22b8d47bf8)
11 Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
13 Lib/test/pickletester.py | 18 ++++++++++++
14 .../2020-07-13-15-06-35.bpo-41288.8mn5P-.rst | 2 ++
15 Modules/_pickle.c | 29 ++++++++++++++-----
16 3 files changed, 41 insertions(+), 8 deletions(-)
17 create mode 100644 Misc/NEWS.d/next/Library/2020-07-13-15-06-35.bpo-41288.8mn5P-.rst
19 diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
20 index 1d88fcb859af8..c576d73349af8 100644
21 --- a/Lib/test/pickletester.py
22 +++ b/Lib/test/pickletester.py
23 @@ -998,6 +998,24 @@ def test_compat_unpickle(self):
24 self.assertIs(type(unpickled), collections.UserDict)
25 self.assertEqual(unpickled, collections.UserDict({1: 2}))
27 + def test_bad_reduce(self):
28 + self.assertEqual(self.loads(b'cbuiltins\nint\n)R.'), 0)
29 + self.check_unpickling_error(TypeError, b'N)R.')
30 + self.check_unpickling_error(TypeError, b'cbuiltins\nint\nNR.')
32 + def test_bad_newobj(self):
33 + error = (pickle.UnpicklingError, TypeError)
34 + self.assertEqual(self.loads(b'cbuiltins\nint\n)\x81.'), 0)
35 + self.check_unpickling_error(error, b'cbuiltins\nlen\n)\x81.')
36 + self.check_unpickling_error(error, b'cbuiltins\nint\nN\x81.')
38 + def test_bad_newobj_ex(self):
39 + error = (pickle.UnpicklingError, TypeError)
40 + self.assertEqual(self.loads(b'cbuiltins\nint\n)}\x92.'), 0)
41 + self.check_unpickling_error(error, b'cbuiltins\nlen\n)}\x92.')
42 + self.check_unpickling_error(error, b'cbuiltins\nint\nN}\x92.')
43 + self.check_unpickling_error(error, b'cbuiltins\nint\n)N\x92.')
45 def test_bad_stack(self):
48 diff --git a/Misc/NEWS.d/next/Library/2020-07-13-15-06-35.bpo-41288.8mn5P-.rst b/Misc/NEWS.d/next/Library/2020-07-13-15-06-35.bpo-41288.8mn5P-.rst
50 index 0000000000000..3c3adbabf16ff
52 +++ b/Misc/NEWS.d/next/Library/2020-07-13-15-06-35.bpo-41288.8mn5P-.rst
54 +Unpickling invalid NEWOBJ_EX opcode with the C implementation raises now
55 +UnpicklingError instead of crashing.
56 diff --git a/Modules/_pickle.c b/Modules/_pickle.c
57 index ef83da02e2e41..329631d7e3b98 100644
58 --- a/Modules/_pickle.c
59 +++ b/Modules/_pickle.c
60 @@ -5515,23 +5515,30 @@ load_newobj_ex(UnpicklerObject *self)
63 if (!PyType_Check(cls)) {
66 PyErr_Format(st->UnpicklingError,
67 "NEWOBJ_EX class argument must be a type, not %.200s",
68 Py_TYPE(cls)->tp_name);
74 if (((PyTypeObject *)cls)->tp_new == NULL) {
78 PyErr_SetString(st->UnpicklingError,
79 "NEWOBJ_EX class argument doesn't have __new__");
83 + if (!PyTuple_Check(args)) {
84 + PyErr_Format(st->UnpicklingError,
85 + "NEWOBJ_EX args argument must be a tuple, not %.200s",
86 + Py_TYPE(args)->tp_name);
89 + if (!PyDict_Check(kwargs)) {
90 + PyErr_Format(st->UnpicklingError,
91 + "NEWOBJ_EX kwargs argument must be a dict, not %.200s",
92 + Py_TYPE(kwargs)->tp_name);
96 obj = ((PyTypeObject *)cls)->tp_new((PyTypeObject *)cls, args, kwargs);
99 @@ -5541,6 +5548,12 @@ load_newobj_ex(UnpicklerObject *self)
101 PDATA_PUSH(self->stack, obj, -1);