Skip to content

Commit dc77f19

Browse files
[3.13] gh-58956: Fix a frame refleak in bdb (GH-128190) (#128947)
* gh-58956: Fix a frame refleak in bdb (GH-128190) (cherry picked from commit 767c89b) Co-authored-by: Tian Gao <[email protected]>
1 parent 9974e71 commit dc77f19

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

Lib/bdb.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ def set_trace(self, frame=None):
382382
frame.f_trace_lines = True
383383
frame = frame.f_back
384384
self.set_stepinstr()
385+
self.enterframe = None
385386
sys.settrace(self.trace_dispatch)
386387

387388
def set_continue(self):
@@ -401,6 +402,7 @@ def set_continue(self):
401402
for frame, (trace_lines, trace_opcodes) in self.frame_trace_lines_opcodes.items():
402403
frame.f_trace_lines, frame.f_trace_opcodes = trace_lines, trace_opcodes
403404
self.frame_trace_lines_opcodes = {}
405+
self.enterframe = None
404406

405407
def set_quit(self):
406408
"""Set quitting attribute to True.

Lib/pdb.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ def forget(self):
383383
if hasattr(self, 'curframe') and self.curframe:
384384
self.curframe.f_globals.pop('__pdb_convenience_variables', None)
385385
self.curframe = None
386+
self.curframe_locals = {}
386387
self.tb_lineno.clear()
387388

388389
def setup(self, f, tb):

Lib/test/test_pdb.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2810,6 +2810,57 @@ def test_pdb_f_trace_lines():
28102810
(Pdb) continue
28112811
"""
28122812

2813+
def test_pdb_frame_refleak():
2814+
"""
2815+
pdb should not leak reference to frames
2816+
2817+
>>> def frame_leaker(container):
2818+
... import sys
2819+
... container.append(sys._getframe())
2820+
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
2821+
... pass
2822+
2823+
>>> def test_function():
2824+
... import gc
2825+
... container = []
2826+
... frame_leaker(container) # c
2827+
... print(len(gc.get_referrers(container[0])))
2828+
... container = []
2829+
... frame_leaker(container) # n c
2830+
... print(len(gc.get_referrers(container[0])))
2831+
... container = []
2832+
... frame_leaker(container) # r c
2833+
... print(len(gc.get_referrers(container[0])))
2834+
2835+
>>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
2836+
... 'continue',
2837+
... 'next',
2838+
... 'continue',
2839+
... 'return',
2840+
... 'continue',
2841+
... ]):
2842+
... test_function()
2843+
> <doctest test.test_pdb.test_pdb_frame_refleak[0]>(4)frame_leaker()
2844+
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
2845+
(Pdb) continue
2846+
1
2847+
> <doctest test.test_pdb.test_pdb_frame_refleak[0]>(4)frame_leaker()
2848+
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
2849+
(Pdb) next
2850+
> <doctest test.test_pdb.test_pdb_frame_refleak[0]>(5)frame_leaker()
2851+
-> pass
2852+
(Pdb) continue
2853+
1
2854+
> <doctest test.test_pdb.test_pdb_frame_refleak[0]>(4)frame_leaker()
2855+
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
2856+
(Pdb) return
2857+
--Return--
2858+
> <doctest test.test_pdb.test_pdb_frame_refleak[0]>(5)frame_leaker()->None
2859+
-> pass
2860+
(Pdb) continue
2861+
1
2862+
"""
2863+
28132864
def test_pdb_function_break():
28142865
"""Testing the line number of break on function
28152866
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed a frame reference leak in :mod:`bdb`.

0 commit comments

Comments
 (0)