Skip to content

Commit

Permalink
pythongh-107901: duplicate blocks with no lineno that have an eval br…
Browse files Browse the repository at this point in the history
…eak and multiple predecessors (python#113950)
  • Loading branch information
iritkatriel authored and aisk committed Feb 11, 2024
1 parent 42f449d commit 68499c1
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 10 deletions.
15 changes: 15 additions & 0 deletions Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,21 @@ async def test(aseq):
code_lines = self.get_code_lines(test.__code__)
self.assertEqual(expected_lines, code_lines)

def test_line_number_synthetic_jump_multiple_predecessors(self):
def f():
for x in it:
try:
if C1:
yield 2
except OSError:
pass

# Ensure that all JUMP_BACKWARDs have line number
code = f.__code__
for inst in dis.Bytecode(code):
if inst.opname == 'JUMP_BACKWARD':
self.assertIsNotNone(inst.positions.lineno)

def test_lineno_of_backward_jump(self):
# Issue gh-107901
def f():
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Compiler duplicates basic blocks that have an eval breaker check, no line number, and multiple predecessors.
32 changes: 22 additions & 10 deletions Python/flowgraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,16 @@ basicblock_exits_scope(const basicblock *b) {
return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode);
}

static inline int
basicblock_has_eval_break(const basicblock *b) {
for (int i = 0; i < b->b_iused; i++) {
if (OPCODE_HAS_EVAL_BREAK(b->b_instr[i].i_opcode)) {
return true;
}
}
return false;
}

static bool
cfg_builder_current_block_is_terminated(cfg_builder *g)
{
Expand Down Expand Up @@ -2246,16 +2256,18 @@ convert_pseudo_ops(basicblock *entryblock)
}

static inline bool
is_exit_without_lineno(basicblock *b) {
if (!basicblock_exits_scope(b)) {
return false;
}
for (int i = 0; i < b->b_iused; i++) {
if (b->b_instr[i].i_loc.lineno >= 0) {
return false;
is_exit_or_eval_check_without_lineno(basicblock *b) {
if (basicblock_exits_scope(b) || basicblock_has_eval_break(b)) {
for (int i = 0; i < b->b_iused; i++) {
if (b->b_instr[i].i_loc.lineno >= 0) {
return false;
}
}
return true;
}
else {
return false;
}
return true;
}


Expand Down Expand Up @@ -2283,7 +2295,7 @@ duplicate_exits_without_lineno(cfg_builder *g)
}
if (is_jump(last)) {
basicblock *target = next_nonempty_block(last->i_target);
if (is_exit_without_lineno(target) && target->b_predecessors > 1) {
if (is_exit_or_eval_check_without_lineno(target) && target->b_predecessors > 1) {
basicblock *new_target = copy_basicblock(g, target);
if (new_target == NULL) {
return ERROR;
Expand All @@ -2303,7 +2315,7 @@ duplicate_exits_without_lineno(cfg_builder *g)
* fall through, and thus can only have a single predecessor */
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
if (BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_iused > 0) {
if (is_exit_without_lineno(b->b_next)) {
if (is_exit_or_eval_check_without_lineno(b->b_next)) {
cfg_instr *last = basicblock_last_instr(b);
assert(last != NULL);
b->b_next->b_instr[0].i_loc = last->i_loc;
Expand Down

0 comments on commit 68499c1

Please sign in to comment.