From 21866c8ed296524f0ca175c0f55b43744c2b30df Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:10:06 +0100 Subject: [PATCH] gh-120367: fix removal of redundant NOPs and jumps after reordering hot-cold blocks (#120425) --- Lib/test/test_compile.py | 27 +++++++++++++++++ ...-06-12-18-50-29.gh-issue-120367.LmXx2y.rst | 2 ++ Python/flowgraph.c | 30 +++++++++++-------- 3 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-50-29.gh-issue-120367.LmXx2y.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index ae23aea08d9..219314b5ce3 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -502,6 +502,33 @@ class TestSpecifics(unittest.TestCase): with self.assertRaisesRegex(TypeError, "NamedExpr target must be a Name"): compile(ast.fix_missing_locations(m), "", "exec") + def test_compile_redundant_jumps_and_nops_after_moving_cold_blocks(self): + # See gh-120367 + code=textwrap.dedent(""" + try: + pass + except: + pass + else: + match name_2: + case b'': + pass + finally: + something + """) + + tree = ast.parse(code) + + # make all instructions locations the same to create redundancies + for node in ast.walk(tree): + if hasattr(node,"lineno"): + del node.lineno + del node.end_lineno + del node.col_offset + del node.end_col_offset + + compile(ast.fix_missing_locations(tree), "", "exec") + def test_compile_ast(self): fname = __file__ if fname.lower().endswith('pyc'): diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-50-29.gh-issue-120367.LmXx2y.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-50-29.gh-issue-120367.LmXx2y.rst new file mode 100644 index 00000000000..2d7212a66f7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-50-29.gh-issue-120367.LmXx2y.rst @@ -0,0 +1,2 @@ +Fix crash in compiler on code with redundant NOPs and JUMPs which show up +after exception handlers are moved to the end of the code. diff --git a/Python/flowgraph.c b/Python/flowgraph.c index aed694aee91..6f30dfcd33e 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1857,6 +1857,22 @@ error: static int resolve_line_numbers(cfg_builder *g, int firstlineno); +static int +remove_redundant_nops_and_jumps(cfg_builder *g) +{ + int removed_nops, removed_jumps; + do { + /* Convergence is guaranteed because the number of + * redundant jumps and nops only decreases. + */ + removed_nops = remove_redundant_nops(g); + RETURN_IF_ERROR(removed_nops); + removed_jumps = remove_redundant_jumps(g); + RETURN_IF_ERROR(removed_jumps); + } while(removed_nops + removed_jumps > 0); + return SUCCESS; +} + /* Perform optimizations on a control flow graph. The consts object should still be in list form to allow new constants to be appended. @@ -1878,17 +1894,7 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache, int firstl } RETURN_IF_ERROR(remove_redundant_nops_and_pairs(g->g_entryblock)); RETURN_IF_ERROR(remove_unreachable(g->g_entryblock)); - - int removed_nops, removed_jumps; - do { - /* Convergence is guaranteed because the number of - * redundant jumps and nops only decreases. - */ - removed_nops = remove_redundant_nops(g); - RETURN_IF_ERROR(removed_nops); - removed_jumps = remove_redundant_jumps(g); - RETURN_IF_ERROR(removed_jumps); - } while(removed_nops + removed_jumps > 0); + RETURN_IF_ERROR(remove_redundant_nops_and_jumps(g)); assert(no_redundant_jumps(g)); return SUCCESS; } @@ -2358,7 +2364,7 @@ push_cold_blocks_to_end(cfg_builder *g) { b->b_next = cold_blocks; if (cold_blocks != NULL) { - RETURN_IF_ERROR(remove_redundant_jumps(g)); + RETURN_IF_ERROR(remove_redundant_nops_and_jumps(g)); } return SUCCESS; }