mirror of
https://github.com/python/cpython.git
synced 2025-08-03 00:23:06 +00:00
bpo-35983: skip trashcan for subclasses (GH-11841)
Add new trashcan macros to deal with a double deallocation that could occur when the `tp_dealloc` of a subclass calls the `tp_dealloc` of a base class and that base class uses the trashcan mechanism. Patch by Jeroen Demeyer.
This commit is contained in:
parent
a2fedd8c91
commit
351c67416b
15 changed files with 189 additions and 121 deletions
|
@ -333,6 +333,49 @@ class CAPITest(unittest.TestCase):
|
|||
br'_Py_NegativeRefcount: Assertion failed: '
|
||||
br'object has negative ref count')
|
||||
|
||||
def test_trashcan_subclass(self):
|
||||
# bpo-35983: Check that the trashcan mechanism for "list" is NOT
|
||||
# activated when its tp_dealloc is being called by a subclass
|
||||
from _testcapi import MyList
|
||||
L = None
|
||||
for i in range(1000):
|
||||
L = MyList((L,))
|
||||
|
||||
def test_trashcan_python_class1(self):
|
||||
self.do_test_trashcan_python_class(list)
|
||||
|
||||
def test_trashcan_python_class2(self):
|
||||
from _testcapi import MyList
|
||||
self.do_test_trashcan_python_class(MyList)
|
||||
|
||||
def do_test_trashcan_python_class(self, base):
|
||||
# Check that the trashcan mechanism works properly for a Python
|
||||
# subclass of a class using the trashcan (this specific test assumes
|
||||
# that the base class "base" behaves like list)
|
||||
class PyList(base):
|
||||
# Count the number of PyList instances to verify that there is
|
||||
# no memory leak
|
||||
num = 0
|
||||
def __init__(self, *args):
|
||||
__class__.num += 1
|
||||
super().__init__(*args)
|
||||
def __del__(self):
|
||||
__class__.num -= 1
|
||||
|
||||
for parity in (0, 1):
|
||||
L = None
|
||||
# We need in the order of 2**20 iterations here such that a
|
||||
# typical 8MB stack would overflow without the trashcan.
|
||||
for i in range(2**20):
|
||||
L = PyList((L,))
|
||||
L.attr = i
|
||||
if parity:
|
||||
# Add one additional nesting layer
|
||||
L = (L,)
|
||||
self.assertGreater(PyList.num, 0)
|
||||
del L
|
||||
self.assertEqual(PyList.num, 0)
|
||||
|
||||
|
||||
class TestPendingCalls(unittest.TestCase):
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue