From 7536730ed6afb948ffa335fc113a0fcd9af0cdbf Mon Sep 17 00:00:00 2001 From: Chanho Lee Date: Sun, 4 Oct 2026 22:47:45 +0900 Subject: [PATCH] Fix store subscr list finalizer deadlock (#8956) * Release replaced list item outside the lock in STORE_SUBSCR_LIST_INT Assisted-by: Claude Code:claude-opus-5-5 * Add a snippet for finalizers reading a list during a specialized store Assisted-by: Claude Code:claude-opus-5-5 --- crates/vm/src/frame.rs | 6 ++++- extra_tests/snippets/vm_specialization.py | 30 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/crates/vm/src/frame.rs b/crates/vm/src/frame.rs index cc54ad6ee..dadc0476b 100644 --- a/crates/vm/src/frame.rs +++ b/crates/vm/src/frame.rs @@ -6430,7 +6430,11 @@ impl ExecutingFrame<'_> { { let mut vec = list.borrow_vec_mut(); if i < vec.len() { - vec[i] = value; + // Unlock before dropping the replaced element; its + // finalizer may access this list. + let old = core::mem::replace(&mut vec[i], value); + drop(vec); + drop(old); return Ok(None); } } diff --git a/extra_tests/snippets/vm_specialization.py b/extra_tests/snippets/vm_specialization.py index b1d201e8a..99b4b78b6 100644 --- a/extra_tests/snippets/vm_specialization.py +++ b/extra_tests/snippets/vm_specialization.py @@ -342,3 +342,33 @@ def module_attribute_custom_dict_key(): module_attribute_custom_dict_key() + + +## STORE_SUBSCR_LIST_INT: the replaced element's finalizer can read the list + + +def store_subscr_list_int_finalizer_reads_list(): + target = [None] + seen = [] + + class Item: + def __init__(self, value): + self.value = value + + def __del__(self): + seen.append((self.value, len(target), target[0] is self)) + + def store(value): + target[0] = value + + for i in range(300): + store(Item(i)) + assert any( + op.opname == "STORE_SUBSCR_LIST_INT" + for op in dis.get_instructions(store, adaptive=True) + ) + store(None) + assert seen == [(i, 1, False) for i in range(300)] + + +store_subscr_list_int_finalizer_reads_list()