Skip to content

Commit 9ec9348

Browse files
committed
Add test for JSON encoder memory leak on recursion error
1 parent 0597100 commit 9ec9348

1 file changed

Lines changed: 33 additions & 2 deletions

File tree

Lib/test/test_json/test_recursion.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
from test import support
22
from test.test_json import PyTest, CTest
3+
import weakref
4+
import gc
5+
36

47

58
class JSONTestObject:
@@ -114,7 +117,35 @@ def default(self, o):
114117
with self.assertRaises(RecursionError):
115118
with support.infinite_recursion(1000):
116119
EndlessJSONEncoder(check_circular=False).encode(5j)
117-
118-
120+
121+
@support.skip_if_unlimited_stack_size
122+
@support.skip_emscripten_stack_overflow()
123+
@support.skip_wasi_stack_overflow()
124+
def test_memory_leak_on_recursion_error(self):
125+
"""Test that no memory leak occurs when a RecursionError is raised."""
126+
weak_refs = []
127+
class LeakTestObj:
128+
pass
129+
130+
def default(obj):
131+
if isinstance(obj, LeakTestObj):
132+
new_obj = LeakTestObj()
133+
weak_refs.append(weakref.ref(new_obj))
134+
return new_obj
135+
raise TypeError
136+
137+
138+
obj = LeakTestObj()
139+
for _ in range(1000):
140+
obj = [obj]
141+
142+
with self.assertRaises(RecursionError):
143+
self.dumps(obj, default=default)
144+
145+
gc.collect()
146+
for i, ref in enumerate(weak_refs):
147+
self.assertIsNone(ref(),
148+
f"Object {i} still alive - memory leak detected!")
149+
119150
class TestPyRecursion(TestRecursion, PyTest): pass
120151
class TestCRecursion(TestRecursion, CTest): pass

0 commit comments

Comments
 (0)