Skip to content

Commit

Permalink
Auto merge of #16915 - 6d7a:master, r=HKalbasi
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Mar 24, 2024
2 parents e265e3d + 142ef76 commit 3dfd4c1
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 6 deletions.
27 changes: 27 additions & 0 deletions crates/hir-ty/src/consteval/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2825,3 +2825,30 @@ fn unsized_local() {
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::UnsizedTemporary(_))),
);
}

#[test]
fn recursive_adt() {
check_fail(
r#"
//- minicore: coerce_unsized, index, slice
pub enum TagTree {
Leaf,
Choice(&'static [TagTree]),
}
const GOAL: TagTree = {
const TAG_TREE: TagTree = TagTree::Choice(&[
{
const VARIANT_TAG_TREE: TagTree = TagTree::Choice(
&[
TagTree::Leaf,
],
);
VARIANT_TAG_TREE
},
]);
TAG_TREE
};
"#,
|e| matches!(e, ConstEvalError::MirEvalError(MirEvalError::StackOverflow)),
);
}
51 changes: 45 additions & 6 deletions crates/hir-ty/src/mir/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1931,7 +1931,11 @@ impl Evaluator<'_> {
ty: &Ty,
locals: &Locals,
mm: &mut ComplexMemoryMap,
stack_depth_limit: usize,
) -> Result<()> {
if stack_depth_limit.checked_sub(1).is_none() {
return Err(MirEvalError::StackOverflow);
}
match ty.kind(Interner) {
TyKind::Ref(_, _, t) => {
let size = this.size_align_of(t, locals)?;
Expand Down Expand Up @@ -1970,7 +1974,14 @@ impl Evaluator<'_> {
if let Some(ty) = check_inner {
for i in 0..count {
let offset = element_size * i;
rec(this, &b[offset..offset + element_size], ty, locals, mm)?;
rec(
this,
&b[offset..offset + element_size],
ty,
locals,
mm,
stack_depth_limit - 1,
)?;
}
}
}
Expand All @@ -1984,7 +1995,14 @@ impl Evaluator<'_> {
let size = this.size_of_sized(inner, locals, "inner of array")?;
for i in 0..len {
let offset = i * size;
rec(this, &bytes[offset..offset + size], inner, locals, mm)?;
rec(
this,
&bytes[offset..offset + size],
inner,
locals,
mm,
stack_depth_limit - 1,
)?;
}
}
chalk_ir::TyKind::Tuple(_, subst) => {
Expand All @@ -1993,7 +2011,14 @@ impl Evaluator<'_> {
let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument
let offset = layout.fields.offset(id).bytes_usize();
let size = this.layout(ty)?.size.bytes_usize();
rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
rec(
this,
&bytes[offset..offset + size],
ty,
locals,
mm,
stack_depth_limit - 1,
)?;
}
}
chalk_ir::TyKind::Adt(adt, subst) => match adt.0 {
Expand All @@ -2008,7 +2033,14 @@ impl Evaluator<'_> {
.bytes_usize();
let ty = &field_types[f].clone().substitute(Interner, subst);
let size = this.layout(ty)?.size.bytes_usize();
rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
rec(
this,
&bytes[offset..offset + size],
ty,
locals,
mm,
stack_depth_limit - 1,
)?;
}
}
AdtId::EnumId(e) => {
Expand All @@ -2027,7 +2059,14 @@ impl Evaluator<'_> {
l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize();
let ty = &field_types[f].clone().substitute(Interner, subst);
let size = this.layout(ty)?.size.bytes_usize();
rec(this, &bytes[offset..offset + size], ty, locals, mm)?;
rec(
this,
&bytes[offset..offset + size],
ty,
locals,
mm,
stack_depth_limit - 1,
)?;
}
}
}
Expand All @@ -2038,7 +2077,7 @@ impl Evaluator<'_> {
Ok(())
}
let mut mm = ComplexMemoryMap::default();
rec(self, bytes, ty, locals, &mut mm)?;
rec(self, bytes, ty, locals, &mut mm, self.stack_depth_limit - 1)?;
Ok(mm)
}

Expand Down

0 comments on commit 3dfd4c1

Please sign in to comment.