f36a7a127d7162a3911cbf1e5828b3f47b96eb15
[feed/packages.git] /
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.
6 (GH-21458) (GH-21461)
7
8 Automerge-Triggered-By: @tiran
9 (cherry picked from commit 4f309abf55f0e6f8950ac13d6ec83c22b8d47bf8)
10
11 Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
12 ---
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
18
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}))
26
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.')
31 +
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.')
37 +
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.')
44 +
45 def test_bad_stack(self):
46 badpickles = [
47 b'.', # STOP
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
49 new file mode 100644
50 index 0000000000000..3c3adbabf16ff
51 --- /dev/null
52 +++ b/Misc/NEWS.d/next/Library/2020-07-13-15-06-35.bpo-41288.8mn5P-.rst
53 @@ -0,0 +1,2 @@
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)
61 }
62
63 if (!PyType_Check(cls)) {
64 - Py_DECREF(kwargs);
65 - Py_DECREF(args);
66 PyErr_Format(st->UnpicklingError,
67 "NEWOBJ_EX class argument must be a type, not %.200s",
68 Py_TYPE(cls)->tp_name);
69 - Py_DECREF(cls);
70 - return -1;
71 + goto error;
72 }
73
74 if (((PyTypeObject *)cls)->tp_new == NULL) {
75 - Py_DECREF(kwargs);
76 - Py_DECREF(args);
77 - Py_DECREF(cls);
78 PyErr_SetString(st->UnpicklingError,
79 "NEWOBJ_EX class argument doesn't have __new__");
80 - return -1;
81 + goto error;
82 + }
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);
87 + goto error;
88 + }
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);
93 + goto error;
94 }
95 +
96 obj = ((PyTypeObject *)cls)->tp_new((PyTypeObject *)cls, args, kwargs);
97 Py_DECREF(kwargs);
98 Py_DECREF(args);
99 @@ -5541,6 +5548,12 @@ load_newobj_ex(UnpicklerObject *self)
100 }
101 PDATA_PUSH(self->stack, obj, -1);
102 return 0;
103 +
104 +error:
105 + Py_DECREF(kwargs);
106 + Py_DECREF(args);
107 + Py_DECREF(cls);
108 + return -1;
109 }
110
111 static int