Author: svn-role Date: Sat May 8 04:00:13 2021 New Revision: 1889654 URL: http://svn.apache.org/viewvc?rev=1889654&view=rev Log: Merge r1889487 from trunk:
* r1889487 swig-py: Fix doubly destroying memory pool with cyclic garbage collector. Votes: +1: jun66j5, futatuki Modified: subversion/branches/1.14.x/ (props changed) subversion/branches/1.14.x/STATUS subversion/branches/1.14.x/subversion/bindings/swig/include/proxy_apr.swg subversion/branches/1.14.x/subversion/bindings/swig/python/tests/pool.py Propchange: subversion/branches/1.14.x/ ------------------------------------------------------------------------------ Merged /subversion/trunk:r1889487 Modified: subversion/branches/1.14.x/STATUS URL: http://svn.apache.org/viewvc/subversion/branches/1.14.x/STATUS?rev=1889654&r1=1889653&r2=1889654&view=diff ============================================================================== --- subversion/branches/1.14.x/STATUS (original) +++ subversion/branches/1.14.x/STATUS Sat May 8 04:00:13 2021 @@ -99,8 +99,3 @@ Veto-blocked changes: Approved changes: ================= - - * r1889487 - swig-py: Fix doubly destroying memory pool with cyclic garbage collector. - Votes: - +1: jun66j5, futatuki Modified: subversion/branches/1.14.x/subversion/bindings/swig/include/proxy_apr.swg URL: http://svn.apache.org/viewvc/subversion/branches/1.14.x/subversion/bindings/swig/include/proxy_apr.swg?rev=1889654&r1=1889653&r2=1889654&view=diff ============================================================================== --- subversion/branches/1.14.x/subversion/bindings/swig/include/proxy_apr.swg (original) +++ subversion/branches/1.14.x/subversion/bindings/swig/include/proxy_apr.swg Sat May 8 04:00:13 2021 @@ -142,9 +142,15 @@ struct apr_pool_t { are still valid""" try: self._is_valid - return True except AttributeError: return False + # We must check whether the parent pool is valid even if + # the pool is valid because weakref's callback is not + # invoked when it is finalized by cyclic garbage collector + if self._parent_pool: + return self._parent_pool.valid() + else: + return True def assert_valid(self): """Assert that this memory_pool is still valid.""" Modified: subversion/branches/1.14.x/subversion/bindings/swig/python/tests/pool.py URL: http://svn.apache.org/viewvc/subversion/branches/1.14.x/subversion/bindings/swig/python/tests/pool.py?rev=1889654&r1=1889653&r2=1889654&view=diff ============================================================================== --- subversion/branches/1.14.x/subversion/bindings/swig/python/tests/pool.py (original) +++ subversion/branches/1.14.x/subversion/bindings/swig/python/tests/pool.py Sat May 8 04:00:13 2021 @@ -19,10 +19,11 @@ # # import unittest, weakref, setup_path -import os, tempfile +import os, tempfile, gc import svn.core, svn.client, libsvn.core from svn.core import * from libsvn.core import application_pool, GenericSWIGWrapper +import utils # Test case for the new automatic pool management infrastructure @@ -208,6 +209,51 @@ class PoolTestCase(unittest.TestCase): # We can still destroy and create pools at will svn_pool_destroy(svn_pool_create()) + def _test_pools_in_circular_reference(self, finalizer=False): + + class Circular(object): + + def __init__(self, pool): + self.pool = pool + self.loop = None + + if finalizer: + def __del__(self): + self.pool = self.loop = None + + def create_circularl(): + pool = Pool(libsvn.core.application_pool) + subpool1 = Pool(pool) + subpool2 = Pool(pool) + circularly1 = Circular(pool) + circularly2 = Circular(subpool2) + circularly3 = Circular(subpool1) + circularly1.loop = circularly3 + circularly2.loop = circularly1 + circularly3.loop = circularly2 + refs = weakref.WeakValueDictionary() + refs['pool'] = pool + refs['subpool1'] = subpool1 + refs['subpool2'] = subpool2 + return refs + + refs = create_circularl() + self.assertEqual({'pool', 'subpool1', 'subpool2'}, + set(name for name, pool in refs.items() + if pool is not None)) + gc.collect() + self.assertEqual(set(), set(name for name, pool in refs.items() + if pool is not None)) + + def test_pools_in_circular_reference_without_finalizer(self): + self._test_pools_in_circular_reference(finalizer=False) + + @unittest.skipIf(not utils.IS_PY3, + "Python 2 cannot collect garbage which involves circular " + "references with finalizer") + def test_pools_in_circular_reference_with_finalizer(self): + self._test_pools_in_circular_reference(finalizer=True) + def suite(): return unittest.defaultTestLoader.loadTestsFromTestCase(PoolTestCase)