Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Lib/linecache.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,12 @@ def lazycache(filename, module_globals):
loader = getattr(spec, 'loader', None)
if loader is None:
loader = module_globals.get('__loader__')
if not ((mod_file := module_globals.get('__file__', None)) and mod_file.endswith(filename)):
def get_lines(name=name, *args, **kwargs):
return ""

cache[filename] = (get_lines,)
return True
get_source = getattr(loader, 'get_source', None)

if name and get_source:
Expand Down
45 changes: 23 additions & 22 deletions Lib/test/test_traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from io import StringIO
import linecache
import sys
import os
import types
import inspect
import builtins
Expand Down Expand Up @@ -36,7 +37,7 @@
test_code.co_positions = lambda _: iter([(6, 6, 0, 0)])
test_frame = namedtuple('frame', ['f_code', 'f_globals', 'f_locals'])
test_tb = namedtuple('tb', ['tb_frame', 'tb_lineno', 'tb_next', 'tb_lasti'])

test_path = os.path.abspath(__file__)

LEVENSHTEIN_DATA_FILE = Path(__file__).parent / 'levenshtein_examples.json'

Expand Down Expand Up @@ -3132,13 +3133,13 @@ class TestFrame(unittest.TestCase):

def test_basics(self):
linecache.clearcache()
linecache.lazycache("f", globals())
f = traceback.FrameSummary("f", 1, "dummy")
linecache.lazycache(test_path, globals())
f = traceback.FrameSummary(test_path, 1, "dummy")
self.assertEqual(f,
("f", 1, "dummy", '"""Test cases for traceback module"""'))
(test_path, 1, "dummy", '"""Test cases for traceback module"""'))
self.assertEqual(tuple(f),
("f", 1, "dummy", '"""Test cases for traceback module"""'))
self.assertEqual(f, traceback.FrameSummary("f", 1, "dummy"))
(test_path, 1, "dummy", '"""Test cases for traceback module"""'))
self.assertEqual(f, traceback.FrameSummary(test_path, 1, "dummy"))
self.assertEqual(f, tuple(f))
# Since tuple.__eq__ doesn't support FrameSummary, the equality
# operator fallbacks to FrameSummary.__eq__.
Expand All @@ -3149,9 +3150,9 @@ def test_basics(self):

def test_lazy_lines(self):
linecache.clearcache()
f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
f = traceback.FrameSummary(test_path, 1, "dummy", lookup_line=False)
self.assertEqual(None, f._lines)
linecache.lazycache("f", globals())
linecache.lazycache(test_path, globals())
self.assertEqual(
'"""Test cases for traceback module"""',
f.line)
Expand Down Expand Up @@ -3197,20 +3198,20 @@ def test_extract_stack_limit(self):

def test_extract_stack_lookup_lines(self):
linecache.clearcache()
linecache.updatecache('/foo.py', globals())
c = test_code('/foo.py', 'method')
linecache.updatecache(test_path, globals())
c = test_code(test_path, 'method')
f = test_frame(c, None, None)
s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
linecache.clearcache()
self.assertEqual(s[0].line, "import sys")

def test_extract_stackup_deferred_lookup_lines(self):
linecache.clearcache()
c = test_code('/foo.py', 'method')
c = test_code(test_path, 'method')
f = test_frame(c, None, None)
s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
self.assertEqual({}, linecache.cache)
linecache.updatecache('/foo.py', globals())
linecache.updatecache(test_path, globals())
self.assertEqual(s[0].line, "import sys")

def test_from_list(self):
Expand All @@ -3236,15 +3237,15 @@ def test_format_smoke(self):
s.format())

def test_locals(self):
linecache.updatecache('/foo.py', globals())
c = test_code('/foo.py', 'method')
linecache.updatecache(test_path, globals())
c = test_code(test_path, 'method')
f = test_frame(c, globals(), {'something': 1})
s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
self.assertEqual(s[0].locals, {'something': '1'})

def test_no_locals(self):
linecache.updatecache('/foo.py', globals())
c = test_code('/foo.py', 'method')
linecache.updatecache(test_path, globals())
c = test_code(test_path, 'method')
f = test_frame(c, globals(), {'something': 1})
s = traceback.StackSummary.extract(iter([(f, 6)]))
self.assertEqual(s[0].locals, None)
Expand Down Expand Up @@ -3602,18 +3603,18 @@ def recurse(n):
def test_lookup_lines(self):
linecache.clearcache()
e = Exception("uh oh")
c = test_code('/foo.py', 'method')
c = test_code(test_path, 'method')
f = test_frame(c, None, None)
tb = test_tb(f, 6, None, 0)
exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
self.assertEqual(linecache.cache, {})
linecache.updatecache('/foo.py', globals())
linecache.updatecache(test_path, globals())
self.assertEqual(exc.stack[0].line, "import sys")

def test_locals(self):
linecache.updatecache('/foo.py', globals())
linecache.updatecache(test_path, globals())
e = Exception("uh oh")
c = test_code('/foo.py', 'method')
c = test_code(test_path, 'method')
f = test_frame(c, globals(), {'something': 1, 'other': 'string', 'unrepresentable': Unrepresentable()})
tb = test_tb(f, 6, None, 0)
exc = traceback.TracebackException(
Expand All @@ -3623,9 +3624,9 @@ def test_locals(self):
{'something': '1', 'other': "'string'", 'unrepresentable': '<local repr() failed>'})

def test_no_locals(self):
linecache.updatecache('/foo.py', globals())
linecache.updatecache(test_path, globals())
e = Exception("uh oh")
c = test_code('/foo.py', 'method')
c = test_code(test_path, 'method')
f = test_frame(c, globals(), {'something': 1})
tb = test_tb(f, 6, None, 0)
exc = traceback.TracebackException(Exception, e, tb)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed traceback leaks global code when exec.