about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-07-27 17:40:48 +0200
committerGitHub <noreply@github.com>2019-07-27 17:40:48 +0200
commitb25d74fa49049a18528605034e414b31860dc0f6 (patch)
treeed8f7c9f2c4bf8dea0ce7284ef29169e66fa4964
parenta13f1f890b53ce7088373235f3e4d3f67a971c67 (diff)
parent0cd71678e17973ed40f898101d01588bf6f6757a (diff)
downloadrust-b25d74fa49049a18528605034e414b31860dc0f6.tar.gz
rust-b25d74fa49049a18528605034e414b31860dc0f6.zip
Rollup merge of #62982 - oli-obk:static_cycle, r=RalfJung
Don't access a static just for its size and alignment

cc @RalfJung

fixes #62189
-rw-r--r--src/librustc_mir/interpret/memory.rs75
-rw-r--r--src/test/ui/consts/static-cycle-error.rs11
2 files changed, 52 insertions, 34 deletions
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 3f2a76a77be..4575784ac37 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -535,41 +535,48 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         id: AllocId,
         liveness: AllocCheck,
     ) -> InterpResult<'static, (Size, Align)> {
-        // Regular allocations.
-        if let Ok(alloc) = self.get(id) {
-            return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align));
-        }
-        // Function pointers.
-        if let Ok(_) = self.get_fn_alloc(id) {
-            return if let AllocCheck::Dereferencable = liveness {
-                // The caller requested no function pointers.
-                err!(DerefFunctionPointer)
-            } else {
-                Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
-            };
-        }
-        // Foreign statics.
-        // Can't do this in the match argument, we may get cycle errors since the lock would
-        // be held throughout the match.
-        let alloc = self.tcx.alloc_map.lock().get(id);
-        match alloc {
-            Some(GlobalAlloc::Static(did)) => {
-                assert!(self.tcx.is_foreign_item(did));
-                // Use size and align of the type
-                let ty = self.tcx.type_of(did);
-                let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
-                return Ok((layout.size, layout.align.abi));
+        // Don't use `self.get` here as that will
+        // a) cause cycles in case `id` refers to a static
+        // b) duplicate a static's allocation in miri
+        match self.alloc_map.get_or(id, || Err(())) {
+            Ok((_, alloc)) => Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
+            Err(()) => {
+                // Not a local allocation, check the global `tcx.alloc_map`.
+
+                // Can't do this in the match argument, we may get cycle errors since the lock would
+                // be held throughout the match.
+                let alloc = self.tcx.alloc_map.lock().get(id);
+                match alloc {
+                    Some(GlobalAlloc::Static(did)) => {
+                        // Use size and align of the type.
+                        let ty = self.tcx.type_of(did);
+                        let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
+                        Ok((layout.size, layout.align.abi))
+                    },
+                    Some(GlobalAlloc::Memory(alloc)) =>
+                        // Need to duplicate the logic here, because the global allocations have
+                        // different associated types than the interpreter-local ones.
+                        Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
+                    Some(GlobalAlloc::Function(_)) => {
+                        if let AllocCheck::Dereferencable = liveness {
+                            // The caller requested no function pointers.
+                            err!(DerefFunctionPointer)
+                        } else {
+                            Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
+                        }
+                    },
+                    // The rest must be dead.
+                    None => if let AllocCheck::MaybeDead = liveness {
+                        // Deallocated pointers are allowed, we should be able to find
+                        // them in the map.
+                        Ok(*self.dead_alloc_map.get(&id)
+                            .expect("deallocated pointers should all be recorded in \
+                                    `dead_alloc_map`"))
+                    } else {
+                        err!(DanglingPointerDeref)
+                    },
+                }
             }
-            _ => {}
-        }
-        // The rest must be dead.
-        if let AllocCheck::MaybeDead = liveness {
-            // Deallocated pointers are allowed, we should be able to find
-            // them in the map.
-            Ok(*self.dead_alloc_map.get(&id)
-                .expect("deallocated pointers should all be recorded in `dead_alloc_map`"))
-        } else {
-            err!(DanglingPointerDeref)
         }
     }
 
diff --git a/src/test/ui/consts/static-cycle-error.rs b/src/test/ui/consts/static-cycle-error.rs
new file mode 100644
index 00000000000..9ce050aae21
--- /dev/null
+++ b/src/test/ui/consts/static-cycle-error.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+struct Foo {
+    foo: Option<&'static Foo>
+}
+
+static FOO: Foo = Foo {
+    foo: Some(&FOO),
+};
+
+fn main() {}