Skip to content

Commit 5ae9172

Browse files
committed
slot_del
1 parent f6d562e commit 5ae9172

File tree

1 file changed

+25
-1
lines changed

1 file changed

+25
-1
lines changed

crates/vm/src/object/core.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,11 @@ impl WeakRefList {
220220
}))
221221
});
222222
let mut inner = unsafe { inner_ptr.as_ref().lock() };
223+
// If obj was cleared but object is still alive (e.g., new weakref
224+
// created during __del__), restore the obj pointer
225+
if inner.obj.is_none() {
226+
inner.obj = Some(NonNull::from(obj));
227+
}
223228
if is_generic && let Some(generic_weakref) = inner.generic_weakref {
224229
let generic_weakref = unsafe { generic_weakref.as_ref() };
225230
if generic_weakref.0.ref_count.get() != 0 {
@@ -835,15 +840,34 @@ impl PyObject {
835840
slot_del: fn(&PyObject, &VirtualMachine) -> PyResult<()>,
836841
) -> Result<(), ()> {
837842
let ret = crate::vm::thread::with_vm(zelf, |vm| {
843+
// Note: inc() from 0 does a double increment (0→2) for thread safety.
844+
// This gives us "permission" to decrement twice.
838845
zelf.0.ref_count.inc();
846+
let after_inc = zelf.strong_count(); // Should be 2
847+
839848
if let Err(e) = slot_del(zelf, vm) {
840849
let del_method = zelf.get_class_attr(identifier!(vm, __del__)).unwrap();
841850
vm.run_unraisable(e, None, del_method);
842851
}
852+
853+
let after_del = zelf.strong_count();
854+
855+
// First decrement
856+
zelf.0.ref_count.dec();
857+
858+
// Check for resurrection: if ref_count increased beyond our expected 2,
859+
// then __del__ created new references (resurrection occurred).
860+
if after_del > after_inc {
861+
// Resurrected - don't do second decrement, leave object alive
862+
return false;
863+
}
864+
865+
// No resurrection - do second decrement to get back to 0
866+
// This matches the double increment from inc()
843867
zelf.0.ref_count.dec()
844868
});
845869
match ret {
846-
// the decref right above set ref_count back to 0
870+
// the decref set ref_count back to 0
847871
Some(true) => Ok(()),
848872
// we've been resurrected by __del__
849873
Some(false) => Err(()),

0 commit comments

Comments
 (0)