Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-122170: Handle ValueError raised by os.stat in linecache #122176

Merged
merged 8 commits into from
Jul 27, 2024
Merged
Show file tree
Hide file tree
Changes from all 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: 4 additions & 2 deletions Lib/linecache.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def checkcache(filename=None):
return
try:
stat = os.stat(fullname)
except OSError:
except (OSError, ValueError):
cache.pop(filename, None)
continue
if size != stat.st_size or mtime != stat.st_mtime:
Expand Down Expand Up @@ -135,10 +135,12 @@ def updatecache(filename, module_globals=None):
try:
stat = os.stat(fullname)
break
except OSError:
except (OSError, ValueError):
pass
else:
return []
except ValueError: # may be raised by os.stat()
return []
try:
with tokenize.open(fullname) as fp:
lines = fp.readlines()
Expand Down
31 changes: 31 additions & 0 deletions Lib/test/test_linecache.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,37 @@ def test_loader(self):
self.assertEqual(linecache.getlines(filename, module_globals),
['source for x.y.z\n'])

def test_invalid_names(self):
for name, desc in [
picnixz marked this conversation as resolved.
Show resolved Hide resolved
('\x00', 'NUL bytes filename'),
(__file__ + '\x00', 'filename with embedded NUL bytes'),
# A filename with surrogate codes. A UnicodeEncodeError is raised
# by os.stat() upon querying, which is a subclass of ValueError.
("\uD834\uDD1E.py", 'surrogate codes (MUSICAL SYMBOL G CLEF)'),
# For POSIX platforms, an OSError will be raised but for Windows
# platforms, a ValueError is raised due to the path_t converter.
# See: https://github.com/python/cpython/issues/122170
('a' * 1_000_000, 'very long filename'),
]:
with self.subTest(f'updatecache: {desc}'):
linecache.clearcache()
lines = linecache.updatecache(name)
self.assertListEqual(lines, [])
self.assertNotIn(name, linecache.cache)

# hack into the cache (it shouldn't be allowed
# but we never know what people do...)
for key, fullname in [(name, 'ok'), ('key', name), (name, name)]:
with self.subTest(f'checkcache: {desc}',
key=key, fullname=fullname):
linecache.clearcache()
linecache.cache[key] = (0, 1234, [], fullname)
linecache.checkcache(key)
self.assertNotIn(key, linecache.cache)

# just to be sure that we did not mess with cache
linecache.clearcache()


class LineCacheInvalidationTests(unittest.TestCase):
def setUp(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Handle :exc:`ValueError`\s raised by :func:`os.stat` in :mod:`linecache`.
Patch by Bénédikt Tran.
Loading