about summary refs log tree commit diff
diff options
context:
space:
mode:
author6d7a <westphal@consider-it.de>2024-03-21 22:57:21 +0100
committer6d7a <westphal@consider-it.de>2024-03-21 22:57:21 +0100
commit7c1be82cd9abe195205bee476c546a7645632af3 (patch)
tree0d9ee80845ac303f5684f4093304fcc257844e68
parent7ef7f442fc34b5eadb1c6ad6433bd6d0c51b056b (diff)
downloadrust-7c1be82cd9abe195205bee476c546a7645632af3.tar.gz
rust-7c1be82cd9abe195205bee476c546a7645632af3.zip
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.
-rw-r--r--crates/hir-ty/src/consteval/tests.rs27
-rw-r--r--crates/hir-ty/src/mir/eval.rs9
2 files changed, 35 insertions, 1 deletions
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 98384c47490..9199663be12 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -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),
+    );
+}
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index fd98141af63..90b8092b4b1 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -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())