Skip to content

Commit 7c1be82

Browse files
committed
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.
1 parent 7ef7f44 commit 7c1be82

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

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

Lines changed: 27 additions & 0 deletions
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_answer(
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+
|b, _| assert_eq!(b[0] % 8, 0),
2853+
);
2854+
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1710,7 +1710,14 @@ impl Evaluator<'_> {
17101710
}
17111711
ConstScalar::Unknown => not_supported!("evaluating unknown const"),
17121712
};
1713-
let patch_map = memory_map.transform_addresses(|b, align| {
1713+
let patch_map = memory_map.transform_addresses(|b, mut align| {
1714+
// Prevent recursive addresses is adts and slices
1715+
match ((&b[..b.len() / 2]).try_into(), HEAP_OFFSET.checked_add(align)) {
1716+
(Ok(arr), Some(new_addr)) if usize::from_le_bytes(arr) == new_addr => {
1717+
align *= 2;
1718+
}
1719+
_ => (),
1720+
};
17141721
let addr = self.heap_allocate(b.len(), align)?;
17151722
self.write_memory(addr, b)?;
17161723
Ok(addr.to_usize())

0 commit comments

Comments
 (0)