From f3e1e27af3c385a5d4c9f4dc102ed4293179fd20 Mon Sep 17 00:00:00 2001 From: Eldar Abusalimov Date: Fri, 24 Oct 2014 14:14:56 +0400 Subject: [PATCH 02/15] (test) (crashers) NULL old_mro and over-decref on reent --- Lib/test/test_mro.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/Lib/test/test_mro.py b/Lib/test/test_mro.py index 106c23b..1d38c93 100644 --- a/Lib/test/test_mro.py +++ b/Lib/test/test_mro.py @@ -36,6 +36,60 @@ class MroTest(unittest.TestCase): self.step += 1 return ret + def test_incomplete_set_bases_on_self(self): + """ + type_set_bases must be aware that type->tp_mro can be NULL. + """ + class M(DebugHelperMeta): + def mro(cls): + if self.step_until(1): + assert cls.__mro__ is None + cls.__bases__ += () + + return type.mro(cls) + + class A(metaclass=M): + pass + + def test_reent_set_bases_on_base(self): + """ + Deep reentrancy must not over-decref old_mro. + """ + class M(DebugHelperMeta): + def mro(cls): + if cls.__mro__ is not None and cls.__name__ == 'B': + # 4-5 steps are usually enough to make it crash somewhere + if self.step_until(10): + A.__bases__ += () + + return type.mro(cls) + + class A(metaclass=M): + pass + class B(A): + pass + B.__bases__ += () + + def test_reent_set_bases_on_direct_base(self): + """ + Similar to test_reent_set_bases_on_base, but may crash differently. + """ + class M(DebugHelperMeta): + def mro(cls): + base = cls.__bases__[0] + if base is not object: + if self.step_until(5): + base.__bases__ += () + + return type.mro(cls) + + class A(metaclass=M): + pass + class B(A): + pass + class C(B): + pass + if __name__ == '__main__': unittest.main() -- 2.1.1