Skip to content

Commit 12fc552

Browse files
authored
Fix list.__repr__ deadlock (RustPython#7275)
* Fix list repr deadlock * Unmark apssing test
1 parent 7847dd1 commit 12fc552

2 files changed

Lines changed: 32 additions & 6 deletions

File tree

Lib/test/test_list.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ def test_list_resize_overflow(self):
120120
with self.assertRaises((MemoryError, OverflowError)):
121121
lst *= size
122122

123-
@unittest.skip("TODO: RUSTPYTHON; hangs")
124123
def test_repr_mutate(self):
125124
class Obj:
126125
@staticmethod

crates/vm/src/builtins/list.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ use crate::{
2222
AsMapping, AsSequence, Comparable, Constructor, Initializer, IterNext, Iterable,
2323
PyComparisonOp, Representable, SelfIter,
2424
},
25-
utils::collection_repr,
2625
vm::VirtualMachine,
2726
};
27+
use rustpython_common::wtf8::Wtf8Buf;
28+
2829
use alloc::fmt;
2930
use core::ops::DerefMut;
3031

@@ -521,14 +522,40 @@ impl Representable for PyList {
521522
if zelf.__len__() == 0 {
522523
return Ok(vm.ctx.intern_str("[]").to_owned());
523524
}
525+
524526
if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
525527
// Clone elements before calling repr to release the read lock.
526528
// Element repr may mutate the list (e.g., list.clear()), which
527529
// needs a write lock and would deadlock if read lock is held.
528-
let elements: Vec<PyObjectRef> = zelf.borrow_vec().to_vec();
529-
Ok(vm
530-
.ctx
531-
.new_str(collection_repr(None, "[", "]", elements.iter(), vm)?))
530+
let mut writer = Wtf8Buf::new();
531+
writer.push_char('[');
532+
533+
let mut elements = zelf.borrow_vec().to_vec();
534+
let mut size = zelf.__len__();
535+
let mut first = true;
536+
let mut i = 0;
537+
while i < size {
538+
if elements.len() != size {
539+
// `repr` mutated the list. refetch it.
540+
elements = zelf.borrow_vec().to_vec();
541+
}
542+
543+
let item = &elements[i];
544+
545+
if first {
546+
first = false;
547+
} else {
548+
writer.push_str(", ");
549+
}
550+
551+
writer.push_wtf8(item.repr(vm)?.as_wtf8());
552+
553+
size = zelf.__len__(); // Refetch list size as `repr` may mutate the list.
554+
i += 1;
555+
}
556+
557+
writer.push_char(']');
558+
Ok(vm.ctx.new_str(writer))
532559
} else {
533560
Ok(vm.ctx.intern_str("[...]").to_owned())
534561
}

0 commit comments

Comments
 (0)