bpo-41295: Reimplement the Carlo Verre "hackcheck" (GH-21528)


Walk down the MRO backwards to find the type that originally defined the final `tp_setattro`, then make sure we are not jumping over intermediate C-level bases with the Python-level call.

Automerge-Triggered-By: @gvanrossum
(cherry picked from commit c53b310e5926266ce267c44a168165cacd786d6e)

Co-authored-by: scoder <stefan_ml@behnel.de>
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 96cc8de2..9e875da 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -4315,6 +4315,42 @@
         else:
             self.fail("Carlo Verre __delattr__ succeeded!")
 
+    def test_carloverre_multi_inherit_valid(self):
+        class A(type):
+            def __setattr__(cls, key, value):
+                type.__setattr__(cls, key, value)
+
+        class B:
+            pass
+
+        class C(B, A):
+            pass
+
+        obj = C('D', (object,), {})
+        try:
+            obj.test = True
+        except TypeError:
+            self.fail("setattr through direct base types should be legal")
+
+    def test_carloverre_multi_inherit_invalid(self):
+        class A(type):
+            def __setattr__(cls, key, value):
+                object.__setattr__(cls, key, value)  # this should fail!
+
+        class B:
+            pass
+
+        class C(B, A):
+            pass
+
+        obj = C('D', (object,), {})
+        try:
+            obj.test = True
+        except TypeError:
+            pass
+        else:
+            self.fail("setattr through indirect base types should be rejected")
+
     def test_weakref_segfault(self):
         # Testing weakref segfault...
         # SF 742911