about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Schneider <oli-obk@users.noreply.github.com>2017-08-28 16:11:48 +0200
committerGitHub <noreply@github.com>2017-08-28 16:11:48 +0200
commit44a360d8ba3cd77e86fcb510808e2b1c550d4c46 (patch)
treea9a59063b49dd176107e30694c42d49596a6f390
parentb93462a8db2794151a653cc0c01c87216c0c3457 (diff)
parent385b5b9fd138a9d27d05c21876665fdc5dca052a (diff)
downloadrust-44a360d8ba3cd77e86fcb510808e2b1c550d4c46.tar.gz
rust-44a360d8ba3cd77e86fcb510808e2b1c550d4c46.zip
Merge pull request #316 from solson/priroda
Fix relocation copying in overlapping copies
-rw-r--r--miri/lib.rs9
-rw-r--r--src/librustc_mir/interpret/memory.rs38
-rw-r--r--src/librustc_mir/interpret/mod.rs2
-rw-r--r--tests/run-pass/btreemap.rs17
4 files changed, 38 insertions, 28 deletions
diff --git a/miri/lib.rs b/miri/lib.rs
index 204746244c8..852a4cbe2aa 100644
--- a/miri/lib.rs
+++ b/miri/lib.rs
@@ -6,11 +6,8 @@
 // From rustc.
 #[macro_use]
 extern crate log;
-extern crate log_settings;
 #[macro_use]
 extern crate rustc;
-extern crate rustc_const_math;
-extern crate rustc_data_structures;
 extern crate syntax;
 
 use rustc::ty::{self, TyCtxt};
@@ -146,9 +143,9 @@ pub fn eval_main<'a, 'tcx: 'a>(
     }
 }
 
-struct Evaluator;
+pub struct Evaluator;
 #[derive(Default)]
-struct EvaluatorData {
+pub struct EvaluatorData {
     /// Environment variables set by `setenv`
     /// Miri does not expose env vars from the host to the emulated program
     pub(crate) env_vars: HashMap<Vec<u8>, MemoryPointer>,
@@ -163,7 +160,7 @@ pub struct TlsEntry<'tcx> {
 }
 
 #[derive(Default)]
-struct MemoryData<'tcx> {
+pub struct MemoryData<'tcx> {
     /// The Key to use for the next thread-local allocation.
     next_thread_local: TlsKey,
 
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 9930555c199..34de9596f24 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -79,7 +79,7 @@ impl LockInfo {
 pub struct AllocId(u64);
 
 #[derive(Debug)]
-enum AllocIdKind {
+pub enum AllocIdKind {
     /// We can't ever have more than `usize::max_value` functions at the same time
     /// since we never "deallocate" functions
     Function(usize),
@@ -89,7 +89,7 @@ enum AllocIdKind {
 }
 
 impl AllocIdKind {
-    fn into_alloc_id(self) -> AllocId {
+    pub fn into_alloc_id(self) -> AllocId {
         match self {
             AllocIdKind::Function(n) => AllocId(n as u64),
             AllocIdKind::Runtime(n) => AllocId((1 << 63) | n),
@@ -103,10 +103,10 @@ impl AllocId {
         self.0 >> 63
     }
     /// Yields everything but the discriminant bits
-    fn index(self) -> u64 {
+    pub fn index(self) -> u64 {
         self.0 & ((1 << 63) - 1)
     }
-    fn into_alloc_id_kind(self) -> AllocIdKind {
+    pub fn into_alloc_id_kind(self) -> AllocIdKind {
         match self.discriminant() {
             0 => AllocIdKind::Function(self.index() as usize),
             1 => AllocIdKind::Runtime(self.index()),
@@ -1088,6 +1088,17 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         let dest = dest.to_ptr()?;
         self.check_relocation_edges(src, size)?;
 
+        // first copy the relocations to a temporary buffer, because
+        // `get_bytes_mut` will clear the relocations, which is correct,
+        // since we don't want to keep any relocations at the target.
+
+        let relocations: Vec<_> = self.relocations(src, size)?
+            .map(|(&offset, &alloc_id)| {
+                // Update relocation offsets for the new positions in the destination allocation.
+                (offset + dest.offset - src.offset, alloc_id)
+            })
+            .collect();
+
         let src_bytes = self.get_bytes_unchecked(src, size, align)?.as_ptr();
         let dest_bytes = self.get_bytes_mut(dest, size, align)?.as_mut_ptr();
 
@@ -1113,7 +1124,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         }
 
         self.copy_undef_mask(src, dest, size)?;
-        self.copy_relocations(src, dest, size)?;
+        // copy back the relocations
+        self.get_mut(dest.alloc_id)?.relocations.extend(relocations);
 
         Ok(())
     }
@@ -1388,22 +1400,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         }
         Ok(())
     }
-
-    fn copy_relocations(
-        &mut self,
-        src: MemoryPointer,
-        dest: MemoryPointer,
-        size: u64,
-    ) -> EvalResult<'tcx> {
-        let relocations: Vec<_> = self.relocations(src, size)?
-            .map(|(&offset, &alloc_id)| {
-                // Update relocation offsets for the new positions in the destination allocation.
-                (offset + dest.offset - src.offset, alloc_id)
-            })
-            .collect();
-        self.get_mut(dest.alloc_id)?.relocations.extend(relocations);
-        Ok(())
-    }
 }
 
 /// Undefined bytes
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index 3a5fdf273a4..603451a9442 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -27,7 +27,7 @@ pub use self::eval_context::{EvalContext, Frame, ResourceLimits, StackPopCleanup
 
 pub use self::lvalue::{Lvalue, LvalueExtra, GlobalId};
 
-pub use self::memory::{AllocId, Memory, MemoryPointer, MemoryKind, HasMemory};
+pub use self::memory::{AllocId, Memory, MemoryPointer, MemoryKind, HasMemory, AllocIdKind};
 
 use self::memory::{PointerArithmetic, Lock, AccessKind};
 
diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs
new file mode 100644
index 00000000000..55e6b07a658
--- /dev/null
+++ b/tests/run-pass/btreemap.rs
@@ -0,0 +1,17 @@
+// mir validation can't cope with `mem::uninitialized::<SomeEnum>()`
+// compile-flags: -Zmir-emit-validate=0
+
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
+pub enum Foo {
+    A(&'static str),
+    _B,
+    _C,
+}
+
+pub fn main() {
+    let mut b = std::collections::BTreeSet::new();
+    b.insert(Foo::A("\'"));
+    b.insert(Foo::A("/="));
+    b.insert(Foo::A("#"));
+    b.insert(Foo::A("0o"));
+}