]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-122170: Handle ValueError raised by os.stat() in linecache (GH-122176)
authorBénédikt Tran <10796600+picnixz@users.noreply.github.com>
Sat, 27 Jul 2024 10:10:42 +0000 (12:10 +0200)
committerGitHub <noreply@github.com>
Sat, 27 Jul 2024 10:10:42 +0000 (10:10 +0000)
Lib/linecache.py
Lib/test/test_linecache.py
Misc/NEWS.d/next/Library/2024-07-23-15-30-23.gh-issue-122170.Z9gi3Y.rst [new file with mode: 0644]

index 3462f1c451ba291658bb1d7a4e6505fc47653f1b..4b38a0464d8747c50a6befde3e86fa0110ab58e6 100644 (file)
@@ -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:
@@ -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()
index 8ac521d72ef13edb183b5250bd3208736b28fdeb..6f5955791407eab834cc198a975d80f2cc92e7d6 100644 (file)
@@ -280,6 +280,37 @@ class LineCacheTests(unittest.TestCase):
         self.assertEqual(linecache.getlines(filename, module_globals),
                          ['source for x.y.z\n'])
 
+    def test_invalid_names(self):
+        for name, desc in [
+            ('\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):
diff --git a/Misc/NEWS.d/next/Library/2024-07-23-15-30-23.gh-issue-122170.Z9gi3Y.rst b/Misc/NEWS.d/next/Library/2024-07-23-15-30-23.gh-issue-122170.Z9gi3Y.rst
new file mode 100644 (file)
index 0000000..7eeb9f6
--- /dev/null
@@ -0,0 +1,2 @@
+Handle :exc:`ValueError`\s raised by :func:`os.stat` in :mod:`linecache`.
+Patch by Bénédikt Tran.