Skip to content

Commit 3dfd4c1

Browse files
committed
Auto merge of rust-lang#16915 - 6d7a:master, r=HKalbasi
fix: Prevent stack overflow in recursive const types In the evaluation of const values of recursive types certain declarations could cause an endless call-loop within the interpreter (hir-ty’s create_memory_map), which would lead to a stack overflow. This commit adds a check that prevents values that contain an address in their value (such as TyKind::Ref) from being allocated at the address they contain. The commit also adds a test for this edge case.
2 parents e265e3d + 142ef76 commit 3dfd4c1

File tree

2 files changed

+72
-6
lines changed

2 files changed

+72
-6
lines changed

crates/hir-ty/src/consteval/tests.rs

+27
Original file line numberDiff line numberDiff line change
@@ -2825,3 +2825,30 @@ fn unsized_local() {
28252825
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::UnsizedTemporary(_))),
28262826
);
28272827
}
2828+
2829+
#[test]
2830+
fn recursive_adt() {
2831+
check_fail(
2832+
r#"
2833+
//- minicore: coerce_unsized, index, slice
2834+
pub enum TagTree {
2835+
Leaf,
2836+
Choice(&'static [TagTree]),
2837+
}
2838+
const GOAL: TagTree = {
2839+
const TAG_TREE: TagTree = TagTree::Choice(&[
2840+
{
2841+
const VARIANT_TAG_TREE: TagTree = TagTree::Choice(
2842+
&[
2843+
TagTree::Leaf,
2844+
],
2845+
);
2846+
VARIANT_TAG_TREE
2847+
},
2848+
]);
2849+
TAG_TREE
2850+
};
2851+
"#,
2852+
|e| matches!(e, ConstEvalError::MirEvalError(MirEvalError::StackOverflow)),
2853+
);
2854+
}

crates/hir-ty/src/mir/eval.rs

+45-6
Original file line numberDiff line numberDiff line change
@@ -1931,7 +1931,11 @@ impl Evaluator<'_> {
19311931
ty: &Ty,
19321932
locals: &Locals,
19331933
mm: &mut ComplexMemoryMap,
1934+
stack_depth_limit: usize,
19341935
) -> Result<()> {
1936+
if stack_depth_limit.checked_sub(1).is_none() {
1937+
return Err(MirEvalError::StackOverflow);
1938+
}
19351939
match ty.kind(Interner) {
19361940
TyKind::Ref(_, _, t) => {
19371941
let size = this.size_align_of(t, locals)?;
@@ -1970,7 +1974,14 @@ impl Evaluator<'_> {
19701974
if let Some(ty) = check_inner {
19711975
for i in 0..count {
19721976
let offset = element_size * i;
1973-
rec(this, &b[offset..offset + element_size], ty, locals, mm)?;
1977+
rec(
1978+
this,
1979+
&b[offset..offset + element_size],
1980+
ty,
1981+
locals,
1982+
mm,
1983+
stack_depth_limit - 1,
1984+
)?;
19741985
}
19751986
}
19761987
}
@@ -1984,7 +1995,14 @@ impl Evaluator<'_> {
19841995
let size = this.size_of_sized(inner, locals, "inner of array")?;
19851996
for i in 0..len {
19861997
let offset = i * size;
1987-
rec(this, &bytes[offset..offset + size], inner, locals, mm)?;
1998+
rec(
1999+
this,
2000+
&bytes[offset..offset + size],
2001+
inner,
2002+
locals,
2003+
mm,
2004+
stack_depth_limit - 1,
2005+
)?;
19882006
}
19892007
}
19902008
chalk_ir::TyKind::Tuple(_, subst) => {
@@ -1993,7 +2011,14 @@ impl Evaluator<'_> {
19932011
let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument
19942012
let offset = layout.fields.offset(id).bytes_usize();
19952013
let size = this.layout(ty)?.size.bytes_usize();
1996-
rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
2014+
rec(
2015+
this,
2016+
&bytes[offset..offset + size],
2017+
ty,
2018+
locals,
2019+
mm,
2020+
stack_depth_limit - 1,
2021+
)?;
19972022
}
19982023
}
19992024
chalk_ir::TyKind::Adt(adt, subst) => match adt.0 {
@@ -2008,7 +2033,14 @@ impl Evaluator<'_> {
20082033
.bytes_usize();
20092034
let ty = &field_types[f].clone().substitute(Interner, subst);
20102035
let size = this.layout(ty)?.size.bytes_usize();
2011-
rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
2036+
rec(
2037+
this,
2038+
&bytes[offset..offset + size],
2039+
ty,
2040+
locals,
2041+
mm,
2042+
stack_depth_limit - 1,
2043+
)?;
20122044
}
20132045
}
20142046
AdtId::EnumId(e) => {
@@ -2027,7 +2059,14 @@ impl Evaluator<'_> {
20272059
l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize();
20282060
let ty = &field_types[f].clone().substitute(Interner, subst);
20292061
let size = this.layout(ty)?.size.bytes_usize();
2030-
rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
2062+
rec(
2063+
this,
2064+
&bytes[offset..offset + size],
2065+
ty,
2066+
locals,
2067+
mm,
2068+
stack_depth_limit - 1,
2069+
)?;
20312070
}
20322071
}
20332072
}
@@ -2038,7 +2077,7 @@ impl Evaluator<'_> {
20382077
Ok(())
20392078
}
20402079
let mut mm = ComplexMemoryMap::default();
2041-
rec(self, bytes, ty, locals, &mut mm)?;
2080+
rec(self, bytes, ty, locals, &mut mm, self.stack_depth_limit - 1)?;
20422081
Ok(mm)
20432082
}
20442083

0 commit comments

Comments
 (0)