Summary
items[0] = value hangs once the store has been specialized to STORE_SUBSCR_LIST_INT, if the element being replaced has a __del__ that reads the same list.
items = [None]
class Item:
def __del__(self):
len(items)
for i in range(6):
items[0] = Item()
print(i, flush=True)
The specialized handler in crates/vm/src/frame.rs assigns with vec[i] = value while it holds the list's write guard, so the old element is dropped under the lock and its finalizer waits on the same lock. The generic path is fine: #8894 made list.__setitem__ release replaced elements outside the lock, and the same loop with items.__setitem__(0, Item()) finishes.
Expected
CPython 3.14.7:
Actual
RustPython ada43c4f (0.6.1) prints two lines and then hangs on the third store, after the instruction has been specialized:
Python Documentation
CPython's handler for the same instruction stores the new item, unlocks the list and only then releases the old one (UNLOCK_OBJECT(list); // unlock before decrefs!): https://github.com/python/cpython/blob/v3.14.7/Python/bytecodes.c#L1093-L1120
Reactions are currently unavailable
Summary
items[0] = value hangs once the store has been specialized to STORE_SUBSCR_LIST_INT, if the element being replaced has a __del__ that reads the same list.
The specialized handler in crates/vm/src/frame.rs assigns with vec[i] = value while it holds the list's write guard, so the old element is dropped under the lock and its finalizer waits on the same lock. The generic path is fine: #8894 made list.__setitem__ release replaced elements outside the lock, and the same loop with items.__setitem__(0, Item()) finishes.
Expected
CPython 3.14.7:
Actual
RustPython ada43c4f (0.6.1) prints two lines and then hangs on the third store, after the instruction has been specialized:
Python Documentation
CPython's handler for the same instruction stores the new item, unlocks the list and only then releases the old one (UNLOCK_OBJECT(list); // unlock before decrefs!): https://github.com/python/cpython/blob/v3.14.7/Python/bytecodes.c#L1093-L1120