Index: Lib/test/test_descr.py =================================================================== --- Lib/test/test_descr.py (revision 67248) +++ Lib/test/test_descr.py (working copy) @@ -4087,6 +4087,24 @@ check(iexpr, c, N1) check(iexpr, c, N2) +def test_lost_getattr(): + # issue 4230 + import gc + class EvilGetattribute(object): + def __getattr__(self, name): + raise AttributeError(name) + def __getattribute__(self, name): + del EvilGetattribute.__getattr__ + for i in range(5): + gc.collect() + raise AttributeError(name) + + try: + # This used to segfault + EvilGetattribute().attr + except AttributeError: + pass + def test_main(): weakref_segfault() # Must be first, somehow wrapper_segfault() @@ -4183,6 +4201,7 @@ vicious_descriptor_nonsense() test_init() notimplemented() + test_lost_getattr() if verbose: print "All OK" Index: Misc/NEWS =================================================================== --- Misc/NEWS (revision 67248) +++ Misc/NEWS (working copy) @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Issue #4230: Fix a crash when a class has a custom __getattr__ and + an evil __getattribute__ method. + - Apply security patches from Apple. CVE-2008-2315. - Issue #2620: Overflow checking when allocating or reallocating memory Index: Objects/typeobject.c =================================================================== --- Objects/typeobject.c (revision 67248) +++ Objects/typeobject.c (working copy) @@ -4594,6 +4594,7 @@ tp->tp_getattro = slot_tp_getattro; return slot_tp_getattro(self, name); } + Py_INCREF(getattr); getattribute = _PyType_Lookup(tp, getattribute_str); if (getattribute == NULL || (getattribute->ob_type == &PyWrapperDescr_Type && @@ -4606,6 +4607,7 @@ PyErr_Clear(); res = PyObject_CallFunction(getattr, "OO", self, name); } + Py_DECREF(getattr); return res; }