Skip to content

Commit a3f2ee8

Browse files
committed
gh-156545: Verify recursion limit restoration during export
1 parent 68dd928 commit a3f2ee8

2 files changed

Lines changed: 18 additions & 4 deletions

File tree

‎Lib/profiling/sampling/stack_collector.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def set_mode(self, mode):
170170
self.stats["mode"] = mode
171171

172172
def export(self, filename):
173-
# export() and json.dumps() recurse to the sampled stack depth.
173+
# Converting the call tree recurses to the sampled stack depth.
174174
old_limit = sys.getrecursionlimit()
175175
sys.setrecursionlimit(old_limit + _FLAMEGRAPH_RECURSION_MARGIN)
176176
try:

‎Lib/test/test_profiling/test_sampling_profiler/test_collectors.py‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
import marshal
55
import opcode
66
import os
7+
import sys
78
import tempfile
89
import unittest
910

10-
from test.support import is_emscripten
11+
from test.support import is_emscripten, set_recursion_limit
1112

1213
try:
1314
import _remote_debugging # noqa: F401
@@ -611,7 +612,6 @@ def test_flamegraph_collector_empty_export_fails(self):
611612
self.assertEqual(os.path.getsize(flamegraph_out.name), 0)
612613

613614
def test_flamegraph_deep_stack_export(self):
614-
"""A deep stack must export instead of raising RecursionError."""
615615
flamegraph_out = tempfile.NamedTemporaryFile(
616616
suffix=".html", delete=False
617617
)
@@ -623,12 +623,26 @@ def test_flamegraph_deep_stack_export(self):
623623
collector.collect(
624624
[MockInterpreterInfo(0, [MockThreadInfo(1, frames)])])
625625

626-
with captured_stdout(), captured_stderr():
626+
with set_recursion_limit(1000), captured_stdout(), captured_stderr():
627627
export_ok = collector.export(flamegraph_out.name)
628+
self.assertEqual(sys.getrecursionlimit(), 1000)
628629

629630
self.assertTrue(export_ok)
630631
self.assertGreater(os.path.getsize(flamegraph_out.name), 0)
631632

633+
def test_flamegraph_export_restores_recursion_limit(self):
634+
collector = FlamegraphCollector(1000)
635+
frame = MockFrameInfo("f.py", 1, "f")
636+
with set_recursion_limit(500), captured_stdout(), captured_stderr():
637+
self.assertFalse(collector.export(None))
638+
self.assertEqual(sys.getrecursionlimit(), 500)
639+
collector.collect([
640+
MockInterpreterInfo(0, [MockThreadInfo(1, [
641+
frame, MockFrameInfo("f.py", 2, "caller")])])])
642+
with self.assertRaises(TypeError):
643+
collector.export(None)
644+
self.assertEqual(sys.getrecursionlimit(), 500)
645+
632646
def test_gecko_collector_basic(self):
633647
"""Test basic GeckoCollector functionality."""
634648
collector = GeckoCollector(1000)

0 commit comments

Comments
 (0)