Repository navigation
gh-130279: Fix missing exception handlers for jumps in loops - #159460
LH-and-FPGA wants to merge 10 commits into
Conversation
| @@ -586,6 +586,13 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) { | |||
| basicblock_addop(backwards_jump, NOT_TAKEN, 0, last->i_loc)); | |||
| RETURN_IF_ERROR( | |||
| basicblock_add_jump(backwards_jump, JUMP, target, last->i_loc)); | |||
There was a problem hiding this comment.
We could add an except arg to basicblock_addop and basicblock_add_jump (pass NULL if there is none).
There was a problem hiding this comment.
Thanks, I'll add an except on those places which replaces the post-hoc fixups.
There was a problem hiding this comment.
While doing this I noticed that the forward-branch NOT_TAKEN in normalize_jumps_in_block() also gets no handler, which leaves a gap in the exception table. It could matter when a sys.monitoring BRANCH_LEFT callback raises. Should I fix it here, or in a separate issue?
| /* The new instructions are covered by the same exception handler as | ||
| * the conditional jump, since the backward jump can raise when it | ||
| * checks the eval breaker. | ||
| */ |
There was a problem hiding this comment.
I don't think this comment is necessary. We copy i_loc and i_except, it makes sense.
|
Does this need to be backported? |
Do you mean fix this for 3.13 3.14 and 3.15? |
|
Yes. |
3.14 and 3.15 have the same code, so I think it should go to both. 3.13 and 3.12 has the backward jump issue as well, but it's security-only now. so how should I backport in general? Thanks |
I found this https://devguide.python.org/getting-started/git-boot-camp/#backporting-merged-changes, so basically I don't need to do anything I think? |
| basicblock_add_jump( | ||
| bb, opcode, target->i_target, target->i_loc)); | ||
| bb, opcode, target->i_target, target->i_loc, | ||
| inst->i_except)); |
There was a problem hiding this comment.
Why are we taking location from target but handler from inst?
There was a problem hiding this comment.
they should be the same in practice. jumps don't change the exception stack, and at this stage the NOPs left by POP_BLOCK haven't been removed yet, so threading never crosses a try boundary ( and I checked by compiling the stdlib with a debug check, and there were no mismatches). But the new jump stands in for target, so does that mean taking both from target is more consistent? Thanks.
There was a problem hiding this comment.
Let's take it from target then, so it doesn't look strange.
I'm seeing some failures in test_dis on the builedbot.
I put the labels for back porting. If it goes smoothly you don't do anything. If there are conflicts you'll need to resolve them (create the back port manually off the 3.14/3.15 branches). |
|
Is this your first PR? If so then add your name to the contributors file. |
When a loop body ends with an
ifwhose false branch jumps back to the loop head, the backward jump ended up outside the exception table ranges of the enclosingtry/with. An exception raised when thatJUMP_BACKWARDchecks the eval breaker (e.g.KeyboardInterrupt, or an async exception set viaPyThreadState_SetAsyncExc) then skipped theexcept/finallyblocks, and__exit__was not called forwithblocks.Two places in Python/flowgraph.c created jump instructions without an exception handler after label_exception_targets() had already run:
Both now copy the handler of the original jump.
KeyboardInterruptnot handled while evaluating a tightwhileloop condition on Python 3.13 #130279