mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 22:01:37 +00:00
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:
parent
7ef7f442fc
commit
7c1be82cd9
2 changed files with 35 additions and 1 deletions
|
@ -2825,3 +2825,30 @@ fn unsized_local() {
|
||||||
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::UnsizedTemporary(_))),
|
|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),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1710,7 +1710,14 @@ impl Evaluator<'_> {
|
||||||
}
|
}
|
||||||
ConstScalar::Unknown => not_supported!("evaluating unknown const"),
|
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)?;
|
let addr = self.heap_allocate(b.len(), align)?;
|
||||||
self.write_memory(addr, b)?;
|
self.write_memory(addr, b)?;
|
||||||
Ok(addr.to_usize())
|
Ok(addr.to_usize())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue