summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJan-Jaap Driessen <jdriessen@minddistrict.com>2020-10-01 13:05:12 +0200
committerJan-Jaap Driessen <jdriessen@minddistrict.com>2020-10-01 13:05:12 +0200
commitca5b7e0c8dceb13d4d2a7d86e49558e2c75fa2dc (patch)
tree72c455bcc46e24dbe42f67edb84d9805e025f579 /src
parent3fc878eb00deb9e2988ef651c74e09e39dd9d49a (diff)
parent93efea7577701231f7d196755436872b649fe1de (diff)
downloadzope-interface-ca5b7e0c8dceb13d4d2a7d86e49558e2c75fa2dc.tar.gz
Merge branch 'master' of github.com:zopefoundation/zope.interface into master
Diffstat (limited to 'src')
-rw-r--r--src/zope/interface/_zope_interface_coptimizations.c2
-rw-r--r--src/zope/interface/tests/test_declarations.py29
2 files changed, 31 insertions, 0 deletions
diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c
index 346e7f2..374311e 100644
--- a/src/zope/interface/_zope_interface_coptimizations.c
+++ b/src/zope/interface/_zope_interface_coptimizations.c
@@ -350,6 +350,7 @@ Spec_traverse(Spec* self, visitproc visit, void* arg)
{
Py_VISIT(self->_implied);
Py_VISIT(self->_dependents);
+ Py_VISIT(self->_bases);
Py_VISIT(self->_v_attrs);
Py_VISIT(self->__iro__);
Py_VISIT(self->__sro__);
@@ -361,6 +362,7 @@ Spec_clear(Spec* self)
{
Py_CLEAR(self->_implied);
Py_CLEAR(self->_dependents);
+ Py_CLEAR(self->_bases);
Py_CLEAR(self->_v_attrs);
Py_CLEAR(self->__iro__);
Py_CLEAR(self->__sro__);
diff --git a/src/zope/interface/tests/test_declarations.py b/src/zope/interface/tests/test_declarations.py
index c8678b5..9ef192a 100644
--- a/src/zope/interface/tests/test_declarations.py
+++ b/src/zope/interface/tests/test_declarations.py
@@ -1078,6 +1078,35 @@ class Test_implementer(Test_classImplements):
self.assertIsNone(spec.inherit,)
self.assertIs(foo.__implemented__, spec) # pylint:disable=no-member
+ def test_does_not_leak_on_unique_classes(self):
+ # Make sure nothing is hanging on to the class or Implements
+ # object after they go out of scope. There was briefly a bug
+ # in 5.x that caused SpecificationBase._bases (in C) to not be
+ # traversed or cleared.
+ # https://github.com/zopefoundation/zope.interface/issues/216
+ import gc
+ from zope.interface.interface import InterfaceClass
+ IFoo = InterfaceClass('IFoo')
+
+ begin_count = len(gc.get_objects())
+
+ for _ in range(1900):
+ class TestClass(object):
+ pass
+
+ self._callFUT(TestClass, IFoo)
+
+ gc.collect()
+
+ end_count = len(gc.get_objects())
+
+ # How many new objects might still be around? In all currently
+ # tested interpreters, there aren't any, so our counts should
+ # match exactly. When the bug existed, in a steady state, the loop
+ # would grow by two objects each iteration
+ fudge_factor = 0
+ self.assertLessEqual(end_count, begin_count + fudge_factor)
+
class Test_implementer_only(Test_classImplementsOnly):