look up __getnewargs__ and __getnewargs_ex__ on the object type (#16251)
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 508e02b..2a9e329 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -4701,6 +4701,20 @@
         for proto in protocols:
             self._check_reduce(proto, obj, listitems=list(obj))
 
+    def test_special_method_lookup(self):
+        protocols = range(pickle.HIGHEST_PROTOCOL + 1)
+        class Picky:
+            def __getstate__(self):
+                return {}
+
+            def __getattr__(self, attr):
+                if attr in ("__getnewargs__", "__getnewargs_ex__"):
+                    raise AssertionError(attr)
+                return None
+        for protocol in protocols:
+            state = {} if protocol >= 2 else None
+            self._check_reduce(protocol, Picky(), state=state)
+
     def _assert_is_copy(self, obj, objcopy, msg=None):
         """Utility method to verify if two objects are copies of each others.
         """
diff --git a/Misc/NEWS b/Misc/NEWS
index c23c35e..ac08255 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 Core and Builtins
 -----------------
 
+- Issue #20261: In pickle, lookup __getnewargs__ and __getnewargs_ex__ on the
+  type of the object.
+
 - Issue #20619: Give the AST nodes of keyword-only arguments a column and line
   number.
 
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 449b6d6..f58960d 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3719,7 +3719,7 @@
 
     /* We first attempt to fetch the arguments for __new__ by calling
        __getnewargs_ex__ on the object. */
-    getnewargs_ex = _PyObject_GetAttrId(obj, &PyId___getnewargs_ex__);
+    getnewargs_ex = _PyObject_LookupSpecial(obj, &PyId___getnewargs_ex__);
     if (getnewargs_ex != NULL) {
         PyObject *newargs = PyObject_CallObject(getnewargs_ex, NULL);
         Py_DECREF(getnewargs_ex);
@@ -3766,16 +3766,13 @@
             return -1;
         }
         return 0;
-    } else {
-        if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
-            return -1;
-        }
-        PyErr_Clear();
+    } else if (PyErr_Occurred()) {
+        return -1;
     }
 
     /* The object does not have __getnewargs_ex__ so we fallback on using
        __getnewargs__ instead. */
-    getnewargs = _PyObject_GetAttrId(obj, &PyId___getnewargs__);
+    getnewargs = _PyObject_LookupSpecial(obj, &PyId___getnewargs__);
     if (getnewargs != NULL) {
         *args = PyObject_CallObject(getnewargs, NULL);
         Py_DECREF(getnewargs);
@@ -3791,11 +3788,8 @@
         }
         *kwargs = NULL;
         return 0;
-    } else {
-        if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
-            return -1;
-        }
-        PyErr_Clear();
+    } else if (PyErr_Occurred()) {
+        return -1;
     }
 
     /* The object does not have __getnewargs_ex__ and __getnewargs__. This may