8000 gh-133371: Don't optimize `LOAD_FAST` instructions whose local is kil… · faster-cpython/cpython@78adb63 · GitHub
[go: up one dir, main page]

Skip to content

Commit 78adb63

Browse files
authored
pythongh-133371: Don't optimize LOAD_FAST instructions whose local is killed by DELETE_FAST (python#133383)
In certain cases it's possible for locals loaded by `LOAD_FAST` instructions to be on the stack when the local is killed by `DEL_FAST`. These `LOAD_FAST` instructions should not be optimized into `LOAD_FAST_BORROW` as the strong reference in the frame is killed while there is still a reference on the stack.
1 parent 2bbcaed commit 78adb63

File tree

3 files changed

+31
-1
lines changed

3 files changed

+31
-1
lines changed

Include/internal/pycore_magic_number.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ Known values:
276276
Python 3.14a7 3621 (Optimize LOAD_FAST opcodes into LOAD_FAST_BORROW)
277277
Python 3.14a7 3622 (Store annotations in different class dict keys)
278278
Python 3.14a7 3623 (Add BUILD_INTERPOLATION & BUILD_TEMPLATE opcodes)
279+
Python 3.14b1 3624 (Don't optimize LOAD_FAST when local is killed by DELETE_FAST)
279280
280281
Python 3.15 will start with 3650
281282
@@ -288,7 +289,7 @@ PC/launcher.c must also be updated.
288289
289290
*/
290291

291-
#define PYC_MAGIC_NUMBER 3623
292+
#define PYC_MAGIC_NUMBER 3624
292293
/* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes
293294
(little-endian) and then appending b'\r\n'. */
294295
#define PYC_MAGIC_NUMBER_TOKEN \

Lib/test/test_peepholer.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import dis
2+
import gc
23
from itertools import combinations, product
34
import opcode
45
import sys
@@ -2472,6 +2473,13 @@ def test_unoptimized_if_support_killed(self):
24722473
]
24732474
self.check(insts, insts)
24742475

2476+
insts = [
2477+
("LOAD_FAST", 0, 1),
2478+
("DELETE_FAST", 0, 2),
2479+
("POP_TOP", None, 3),
2480+
]
2481+
self.check(insts, insts)
2482+
24752483
def test_unoptimized_if_aliased(self):
24762484
insts = [
24772485
("LOAD_FAST", 0, 1),
@@ -2606,6 +2614,22 @@ def test_send(self):
26062614
]
26072615
self.cfg_optimization_test(insts, expected, consts=[None])
26082616

2617+
def test_del_in_finally(self):
2618+
# This loads `obj` onto the stack, executes `del obj`, then returns the
2619+
# `obj` from the stack. See gh-133371 for more details.
2620+
def create_obj():
2621+
obj = [42]
2622+
try:
2623+
return obj
2624+
finally:
2625+
del obj
2626+
2627+
obj = create_obj()
2628+
# The crash in the linked issue happens while running GC during
2629+
# interpreter finalization, so run it here manually.
2630+
gc.collect()
2631+
self.assertEqual(obj, [42])
2632+
26092633

26102634

26112635
if __name__ == "__main__":

Python/flowgraph.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2795,6 +2795,11 @@ optimize_load_fast(cfg_builder *g)
27952795
assert(opcode != EXTENDED_ARG);
27962796
switch (opcode) {
27972797
// Opcodes that load and store locals
2798+
case DELETE_FAST: {
2799+
kill_local(instr_flags, &refs, oparg);
2800+
break;
2801+
}
2802+
27982803
case LOAD_FAST: {
27992804
PUSH_REF(i, oparg);
28002805
break;

0 commit comments

Comments
 (0)
0