Skip to content

Commit b347aa5

Browse files
Fix stack overflow in rustc_ast::ptr::P<_> destructor
In rustc_ast, an Expr contains an ExprKind, which can contain a P<Expr>. To prevent the stack from overflowing when dropping an Expr, one of the types must use ManuallyDrop for its fields. Since both Expr and ExprKind are frequently deconstructed into their fields using match expressions, I chose to attach it to P::ptr.
1 parent a2f4017 commit b347aa5

File tree

1 file changed

+39
-20
lines changed

1 file changed

+39
-20
lines changed

compiler/rustc_ast/src/ptr.rs

+39-20
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,36 @@
2121
//! implementation changes (using a special thread-local heap, for example).
2222
//! Moreover, a switch to, e.g., `P<'a, T>` would be easy and mostly automated.
2323
24+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
25+
use rustc_data_structures::stack::ensure_sufficient_stack;
26+
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
27+
2428
use std::fmt::{self, Debug, Display};
2529
use std::iter::FromIterator;
30+
use std::mem::ManuallyDrop;
2631
use std::ops::{Deref, DerefMut};
2732
use std::{slice, vec};
2833

29-
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
30-
31-
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
3234
/// An owned smart pointer.
3335
pub struct P<T: ?Sized> {
34-
ptr: Box<T>,
36+
ptr: ManuallyDrop<Box<T>>,
3537
}
3638

3739
/// Construct a `P<T>` from a `T` value.
3840
#[allow(non_snake_case)]
3941
pub fn P<T: 'static>(value: T) -> P<T> {
40-
P { ptr: Box::new(value) }
42+
P::from_box(Box::new(value))
43+
}
44+
45+
impl<T: ?Sized> P<T> {
46+
const fn from_box(ptr: Box<T>) -> P<T> {
47+
P { ptr: ManuallyDrop::new(ptr) }
48+
}
49+
50+
fn into_box(self) -> Box<T> {
51+
let mut this = ManuallyDrop::new(self);
52+
unsafe { ManuallyDrop::take(&mut this.ptr) }
53+
}
4154
}
4255

4356
impl<T: 'static> P<T> {
@@ -47,32 +60,38 @@ impl<T: 'static> P<T> {
4760
where
4861
F: FnOnce(T) -> U,
4962
{
50-
f(*self.ptr)
63+
f(*self.into_box())
5164
}
5265

5366
/// Equivalent to `and_then(|x| x)`.
5467
pub fn into_inner(self) -> T {
55-
*self.ptr
68+
*self.into_box()
5669
}
5770

5871
/// Produce a new `P<T>` from `self` without reallocating.
59-
pub fn map<F>(mut self, f: F) -> P<T>
72+
pub fn map<F>(self, f: F) -> P<T>
6073
where
6174
F: FnOnce(T) -> T,
6275
{
63-
let x = f(*self.ptr);
64-
*self.ptr = x;
65-
66-
self
76+
let mut ptr = self.into_box();
77+
*ptr = f(*ptr);
78+
P::from_box(ptr)
6779
}
6880

6981
/// Optionally produce a new `P<T>` from `self` without reallocating.
70-
pub fn filter_map<F>(mut self, f: F) -> Option<P<T>>
82+
pub fn filter_map<F>(self, f: F) -> Option<P<T>>
7183
where
7284
F: FnOnce(T) -> Option<T>,
7385
{
74-
*self.ptr = f(*self.ptr)?;
75-
Some(self)
86+
let mut ptr = self.into_box();
87+
*ptr = f(*ptr)?;
88+
Some(P::from_box(ptr))
89+
}
90+
}
91+
92+
impl<T: ?Sized> Drop for P<T> {
93+
fn drop(&mut self) {
94+
ensure_sufficient_stack(|| unsafe { ManuallyDrop::drop(&mut self.ptr) });
7695
}
7796
}
7897

@@ -98,7 +117,7 @@ impl<T: 'static + Clone> Clone for P<T> {
98117

99118
impl<T: ?Sized + Debug> Debug for P<T> {
100119
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101-
Debug::fmt(&self.ptr, f)
120+
Debug::fmt(&*self.ptr, f)
102121
}
103122
}
104123

@@ -110,7 +129,7 @@ impl<T: Display> Display for P<T> {
110129

111130
impl<T> fmt::Pointer for P<T> {
112131
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113-
fmt::Pointer::fmt(&self.ptr, f)
132+
fmt::Pointer::fmt(&*self.ptr, f)
114133
}
115134
}
116135

@@ -128,17 +147,17 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<T> {
128147

129148
impl<T> P<[T]> {
130149
pub const fn new() -> P<[T]> {
131-
P { ptr: Box::default() }
150+
P::from_box(Box::default())
132151
}
133152

134153
#[inline(never)]
135154
pub fn from_vec(v: Vec<T>) -> P<[T]> {
136-
P { ptr: v.into_boxed_slice() }
155+
P::from_box(v.into_boxed_slice())
137156
}
138157

139158
#[inline(never)]
140159
pub fn into_vec(self) -> Vec<T> {
141-
self.ptr.into_vec()
160+
self.into_box().into_vec()
142161
}
143162
}
144163

0 commit comments

Comments
 (0)