diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index a0a11966ebf3c1..2eefb82f60e078 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -5,6 +5,7 @@ import textwrap import threading import unittest +import warnings import weakref try: import _testcapi @@ -222,6 +223,30 @@ def test_f_lineno_del_segfault(self): with self.assertRaises(AttributeError): del f.f_lineno + def test_f_lineno_deep_stack_swap(self): + fors = " ".join(f"for v{i} in range(1)" for i in range(11)) + params = ", ".join(f"v{i}=None" for i in range(11)) + ns = {} + exec(f"def f({params}):\n return [0 {fors}]\n", ns) + f = ns["f"] + + jumped = [] + + def tracer(frame, event, arg): + if (event == 'line' and frame.f_code is f.__code__ + and not jumped): + jumped.append(None) + frame.f_lineno = frame.f_lineno + return tracer + + with warnings.catch_warnings(): + warnings.simplefilter('ignore', RuntimeWarning) + sys.settrace(tracer) + try: + self.assertEqual(f(), [0]) + finally: + sys.settrace(None) + def test_f_trace(self): f, _, _ = self.make_frames() def tracer(*args): diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 61be2beca22d15..38f117e61345df 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -1320,7 +1320,8 @@ stack_swap(int64_t stack, int n) Kind to_swap = peek(stack, n); Kind top = top_of_stack(stack); int shift = BITS_PER_BLOCK*(n-1); - int64_t replaced_low = (stack & ~(MASK << shift)) | (top << shift); + int64_t replaced_low = (stack & ~((int64_t)MASK << shift)) + | ((int64_t)top << shift); int64_t replaced_top = (replaced_low & ~MASK) | to_swap; return replaced_top; }