From abe2e5a2afb7c32065276833ca84210e47499280 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 29 Aug 2022 13:07:44 +0300 Subject: [PATCH 1/3] gh-95196: Disable incorrect pickling of the C implemented classmethod descriptors --- Lib/test/pickletester.py | 21 ++++++++++++++++++- ...2-08-29-13-06-58.gh-issue-95196.eGRR4b.rst | 1 + Objects/descrobject.c | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 21419e11c87497..c0267c2663f7c7 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -2776,6 +2776,15 @@ def pie(self): unpickled = self.loads(self.dumps(method, proto)) self.assertEqual(method(obj), unpickled(obj)) + descriptors = ( + PyMethodsTest.__dict__['cheese'], + PyMethodsTest.__dict__['wine'], + ) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + for descr in descriptors: + with self.subTest(proto=proto, descr=descr): + self.assertRaises(TypeError, self.dumps, descr, proto) + def test_c_methods(self): global Subclass class Subclass(tuple): @@ -2805,12 +2814,22 @@ class Nested(str): (Subclass.Nested("sweet").count, ("e",)), (Subclass.Nested.count, (Subclass.Nested("sweet"), "e")), ) - for proto in range(pickle.HIGHEST_PROTOCOL + 1): + #for proto in range(pickle.HIGHEST_PROTOCOL + 1): + for proto in [5]: for method, args in c_methods: with self.subTest(proto=proto, method=method): unpickled = self.loads(self.dumps(method, proto)) self.assertEqual(method(*args), unpickled(*args)) + descriptors = ( + bytearray.__dict__['maketrans'], + dict.__dict__['fromkeys'], + ) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + for descr in descriptors: + with self.subTest(proto=proto, descr=descr): + self.assertRaises(TypeError, self.dumps, descr, proto) + def test_compat_pickle(self): tests = [ (range(1, 7), '__builtin__', 'xrange'), diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst new file mode 100644 index 00000000000000..37534fa1752550 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst @@ -0,0 +1 @@ +Disable incorrect pickling of the C implemented classmethod descriptors. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 82570e085143ed..a2974f91aaaec3 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -776,7 +776,7 @@ PyTypeObject PyClassMethodDescr_Type = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - descr_methods, /* tp_methods */ + 0, /* tp_methods */ descr_members, /* tp_members */ method_getset, /* tp_getset */ 0, /* tp_base */ From d79301df32808574d3ab914e85e4f0eb0cc403ee Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 29 Aug 2022 17:51:19 +0300 Subject: [PATCH 2/3] Fix debugging remnants. --- Lib/test/pickletester.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index c0267c2663f7c7..0f35c9de743b39 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -2814,8 +2814,7 @@ class Nested(str): (Subclass.Nested("sweet").count, ("e",)), (Subclass.Nested.count, (Subclass.Nested("sweet"), "e")), ) - #for proto in range(pickle.HIGHEST_PROTOCOL + 1): - for proto in [5]: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): for method, args in c_methods: with self.subTest(proto=proto, method=method): unpickled = self.loads(self.dumps(method, proto)) From dadbf009c51b52f1f8a5066c798b0c3d4bba53c4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 5 Oct 2022 13:06:06 +0300 Subject: [PATCH 3/3] Add some comments. --- Lib/test/pickletester.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 0f35c9de743b39..499f80a15f3422 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -2777,8 +2777,8 @@ def pie(self): self.assertEqual(method(obj), unpickled(obj)) descriptors = ( - PyMethodsTest.__dict__['cheese'], - PyMethodsTest.__dict__['wine'], + PyMethodsTest.__dict__['cheese'], # static method descriptor + PyMethodsTest.__dict__['wine'], # class method descriptor ) for proto in range(pickle.HIGHEST_PROTOCOL + 1): for descr in descriptors: @@ -2821,8 +2821,8 @@ class Nested(str): self.assertEqual(method(*args), unpickled(*args)) descriptors = ( - bytearray.__dict__['maketrans'], - dict.__dict__['fromkeys'], + bytearray.__dict__['maketrans'], # built-in static method descriptor + dict.__dict__['fromkeys'], # built-in class method descriptor ) for proto in range(pickle.HIGHEST_PROTOCOL + 1): for descr in descriptors: