diff --git a/Lib/inspect.py b/Lib/inspect.py index 6ca91e401a5eae..18bed9028ed8ab 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -864,7 +864,12 @@ def findsource(object): lnum = object.co_firstlineno - 1 pat = re.compile(r'^(\s*def\s)|(\s*async\s+def\s)|(.*(? 0: - if pat.match(lines[lnum]): break + try: + line = lines[lnum] + except IndexError: + raise OSError('lineno is out of bounds') + if pat.match(line): + break lnum = lnum - 1 return lines, lnum raise OSError('could not find code object') diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 05485a0bc05754..d9e26a30336676 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -710,6 +710,17 @@ def test_findsource_without_filename(self): self.assertRaises(IOError, inspect.findsource, co) self.assertRaises(IOError, inspect.getsource, co) + def test_findsource_with_out_of_bounds_lineno(self): + mod_len = len(inspect.getsource(mod)) + src = '\n' * 2* mod_len + "def f(): pass" + co = compile(src, mod.__file__, "exec") + g, l = {}, {} + eval(co, g, l) + func = l['f'] + self.assertEqual(func.__code__.co_firstlineno, 1+2*mod_len) + with self.assertRaisesRegex(IOError, "lineno is out of bounds"): + inspect.findsource(func) + def test_getsource_on_method(self): self.assertSourceEqual(mod2.ClassWithMethod.method, 118, 119) diff --git a/Misc/NEWS.d/next/Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst b/Misc/NEWS.d/next/Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst new file mode 100644 index 00000000000000..655781e3d2eddb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-03-22-22-24.bpo-17735.Qsaaue.rst @@ -0,0 +1,4 @@ +:func:`inspect.findsource` now raises :exc:`OSError` instead of +:exc:`IndexError` when :attr:`co_lineno` of a code object is greater than the +file length. This can happen, for example, when a file is edited after it was +imported. PR by Irit Katriel.