Skip to content

Commit 6c12ca3

Browse files
committed
auto merge of #8297 : brson/rust/dlist-dtor, r=brson
The compiler-generated dtor for DList recurses deeply to drop Nodes. For big lists this can overflow the stack. This is a problem for the new scheduler, where split stacks are not implemented. Thanks @blake2-ppc
2 parents dc5b0b9 + 4898a0d commit 6c12ca3

File tree

1 file changed

+38
-4
lines changed

1 file changed

+38
-4
lines changed

src/libextra/dlist.rs

+38-4
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ impl<T> Rawlink<T> {
9292
Some(unsafe { cast::transmute(self.p) })
9393
}
9494
}
95+
96+
/// Return the `Rawlink` and replace with `Rawlink::none()`
97+
fn take(&mut self) -> Rawlink<T> {
98+
util::replace(self, Rawlink::none())
99+
}
95100
}
96101

97102
impl<T> Clone for Rawlink<T> {
@@ -280,13 +285,16 @@ impl<T> DList<T> {
280285
/// Add all elements from `other` to the end of the list
281286
///
282287
/// O(1)
283-
pub fn append(&mut self, other: DList<T>) {
288+
pub fn append(&mut self, mut other: DList<T>) {
284289
match self.list_tail.resolve() {
285290
None => *self = other,
286291
Some(tail) => {
287-
match other {
288-
DList{list_head: None, _} => return,
289-
DList{list_head: Some(node), list_tail: o_tail, length: o_length} => {
292+
// Carefully empty `other`.
293+
let o_tail = other.list_tail.take();
294+
let o_length = other.length;
295+
match other.list_head.take() {
296+
None => return,
297+
Some(node) => {
290298
tail.next = link_with_prev(node, self.list_tail);
291299
self.list_tail = o_tail;
292300
self.length += o_length;
@@ -404,6 +412,32 @@ impl<T: Ord> DList<T> {
404412
}
405413
}
406414

415+
#[unsafe_destructor]
416+
impl<T> Drop for DList<T> {
417+
fn drop(&self) {
418+
let mut_self = unsafe {
419+
cast::transmute_mut(self)
420+
};
421+
// Dissolve the dlist in backwards direction
422+
// Just dropping the list_head can lead to stack exhaustion
423+
// when length is >> 1_000_000
424+
let mut tail = mut_self.list_tail;
425+
loop {
426+
match tail.resolve() {
427+
None => break,
428+
Some(prev) => {
429+
prev.next.take(); // release ~Node<T>
430+
tail = prev.prev;
431+
}
432+
}
433+
}
434+
mut_self.length = 0;
435+
mut_self.list_head = None;
436+
mut_self.list_tail = Rawlink::none();
437+
}
438+
}
439+
440+
407441
impl<'self, A> Iterator<&'self A> for DListIterator<'self, A> {
408442
#[inline]
409443
fn next(&mut self) -> Option<&'self A> {

0 commit comments

Comments
 (0)