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.
This commit is contained in:
6d7a 2024-03-21 22:57:21 +01:00
parent 7ef7f442fc
commit 7c1be82cd9
2 changed files with 35 additions and 1 deletions

View file

@ -2825,3 +2825,30 @@ fn unsized_local() {
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::UnsizedTemporary(_))),
);
}
#[test]
fn recursive_adt() {
check_answer(
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
};
"#,
|b, _| assert_eq!(b[0] % 8, 0),
);
}

View file

@ -1710,7 +1710,14 @@ impl Evaluator<'_> {
}
ConstScalar::Unknown => not_supported!("evaluating unknown const"),
};
let patch_map = memory_map.transform_addresses(|b, align| {
let patch_map = memory_map.transform_addresses(|b, mut align| {
// Prevent recursive addresses is adts and slices
match ((&b[..b.len() / 2]).try_into(), HEAP_OFFSET.checked_add(align)) {
(Ok(arr), Some(new_addr)) if usize::from_le_bytes(arr) == new_addr => {
align *= 2;
}
_ => (),
};
let addr = self.heap_allocate(b.len(), align)?;
self.write_memory(addr, b)?;
Ok(addr.to_usize())