8000 gh-122170: Handle `ValueError` raised by `os.stat` in `linecache` by picnixz · Pull Request #122176 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

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

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

Merged
merged 8 commits into from
Jul 27, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
address review
  • Loading branch information
picnixz committed Jul 26, 2024
commit 27eaa98db0b6d136fe6f9688ee695299cc391f6f
11 changes: 1 addition & 10 deletions Lib/linecache.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,6 @@ def checkcache(filename=None):
try:
stat = os.stat(fullname)
except (OSError, ValueError):
# ValueError may happen on Windows platforms for long paths or
# on any platform when the filename has embedded null bytes.
#
# See: https://github.com/python/cpython/issues/122170.
cache.pop(filename, None)
continue
if size != stat.st_size or mtime != stat.st_mtime:
Expand Down Expand Up @@ -143,12 +139,7 @@ def updatecache(filename, module_globals=None):
pass
else:
return []
except ValueError:
# ValueError may happen on Windows platforms for long paths or
# on any platform when the filename has embedded null bytes.
#
# In this case, we will not even try to find the path using lazy
# loading or alternative techniques.
except ValueError: # may be raised by os.stat()
return []
try:
with tokenize.open(fullname) as fp:
Expand Down
72 changes: 36 additions & 36 deletions Lib/test/test_linecache.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,46 +281,46 @@ def test_loader(self):
['source for x.y.z\n'])

def test_embedded_null_bytes(self):
NUL = '\x00'
linecache.clearcache()
lines = linecache.updatecache(NUL)
self.assertListEqual(lines, [])
self.assertNotIn(NUL, linecache.cache)

# hack into the cache (it shouldn't be allowed
# but we never know what people do...)
linecache.clearcache()
linecache.cache[NUL] = (0, 1234, [], 'FULLNAME')
linecache.checkcache(NUL)
self.assertNotIn(NUL, linecache.cache)

linecache.clearcache()
linecache.cache[NUL] = (0, 1234, [], NUL)
linecache.checkcache(NUL)
self.assertNotIn(NUL, linecache.cache)
for name in ['\x00', __file__ + '\x00']:
with self.subTest('updatecache', badname=name):
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('checkcache', 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()

def test_long_filename(self):
# For POSIX platforms, an OSError will be raised and will take
# the usual path handling. For Windows platforms, a ValueError
# is raised instead but linecache will handle it as if it were
# an OSError in this case.
#
# See: https://github.com/python/cpython/issues/122170

linecache.clearcache()
lines = linecache.updatecache('a' * 9999)
self.assertListEqual(lines, [])
self.assertNotIn('a' * 9999, linecache.cache)

# hack into the cache (it shouldn't be allowed
# but we never know what people do...)
linecache.clearcache()
linecache.cache['smallname'] = (0, 1234, [], 'a' * 9999)
linecache.checkcache('smallname')
self.assertNotIn('smallname', linecache.cache)
def test_invalid_names(self):
for name, desc in [
# 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.
70E8 # 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)

with self.subTest(f'checkcache: {desc}'):
linecache.clearcache()
linecache.cache['key'] = (0, 1234, [], name)
linecache.checkcache('key')
self.assertNotIn('key', linecache.cache)

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