From abe2e5a2afb7c32065276833ca84210e47499280 Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
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 <storchaka@gmail.com>
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 <storchaka@gmail.com>
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: