]> git.lizzy.rs Git - rust.git/commitdiff
miri loop detector hashing: fix enum hashing to also consider discriminant; do not...
authorRalf Jung <post@ralfj.de>
Sun, 9 Sep 2018 08:06:39 +0000 (10:06 +0200)
committerRalf Jung <post@ralfj.de>
Sun, 9 Sep 2018 08:53:36 +0000 (10:53 +0200)
standalone miri is not interested in loop detection

src/librustc_mir/const_eval.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/machine.rs
src/librustc_mir/interpret/place.rs
src/librustc_mir/interpret/snapshot.rs
src/librustc_mir/interpret/step.rs

index 154830c2e77e07277bc1fd3ea8ed7dc1fe10ed8e..82cc1b7f66166a848597ea814a7f99be8bce9dbd 100644 (file)
@@ -239,6 +239,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
     type MemoryKinds = !;
 
     const MUT_STATIC_KIND: Option<!> = None; // no mutating of statics allowed
+    const DETECT_LOOPS: bool = true;
 
     fn find_fn<'a>(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
index f7277f8d27610b3fb5ac780e62caf498210da9d1..740d4e038df7ebadf771e2feb0b17652cf361d2d 100644 (file)
@@ -65,6 +65,8 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
     /// detector period.
     pub(super) steps_since_detector_enabled: isize,
 
+    /// Extra state to detect loops.
+    /// FIXME: Move this to the CTFE machine's state, out of the general miri engine.
     pub(super) loop_detector: InfiniteLoopDetector<'a, 'mir, 'tcx, M>,
 }
 
@@ -110,6 +112,7 @@ pub struct Frame<'mir, 'tcx: 'mir> {
     pub stmt: usize,
 }
 
+// Not using the macro because that does not support types depending on 'tcx
 impl<'a, 'mir, 'tcx: 'mir> HashStable<StableHashingContext<'a>> for Frame<'mir, 'tcx> {
     fn hash_stable<W: StableHasherResult>(
         &self,
@@ -144,11 +147,14 @@ pub enum StackPopCleanup {
     None { cleanup: bool },
 }
 
+// Can't use the macro here because that does not support named enum fields.
 impl<'a> HashStable<StableHashingContext<'a>> for StackPopCleanup {
     fn hash_stable<W: StableHasherResult>(
         &self,
         hcx: &mut StableHashingContext<'a>,
-        hasher: &mut StableHasher<W>) {
+        hasher: &mut StableHasher<W>)
+    {
+        mem::discriminant(self).hash_stable(hcx, hasher);
         match self {
             StackPopCleanup::Goto(ref block) => block.hash_stable(hcx, hasher),
             StackPopCleanup::None { cleanup } => cleanup.hash_stable(hcx, hasher),
index 61963f6d3d354560828405c7cbdd9f4fa758b49f..f33cb4791029a8ae9afb3f1259626964e5336868 100644 (file)
 //! This separation exists to ensure that no fancy miri features like
 //! interpreting common C functions leak into CTFE.
 
-use std::hash::Hash;
-
 use rustc::hir::def_id::DefId;
-use rustc::ich::StableHashingContext;
 use rustc::mir::interpret::{Allocation, EvalResult, Scalar};
 use rustc::mir;
 use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
-use rustc_data_structures::stable_hasher::HashStable;
 
 use super::{EvalContext, PlaceTy, OpTy};
 
 /// Methods of this trait signifies a point where CTFE evaluation would fail
 /// and some use case dependent behaviour can instead be applied
-pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash + for<'a> HashStable<StableHashingContext<'a>> {
+pub trait Machine<'mir, 'tcx>: Clone + Eq {
     /// Additional data that can be accessed via the Memory
-    type MemoryData: Clone + Eq + Hash + for<'a> HashStable<StableHashingContext<'a>>;
+    type MemoryData: Clone + Eq;
 
     /// Additional memory kinds a machine wishes to distinguish from the builtin ones
-    type MemoryKinds: ::std::fmt::Debug + Copy + Clone + Eq + Hash;
+    type MemoryKinds: ::std::fmt::Debug + Copy + Clone + Eq;
 
     /// The memory kind to use for mutated statics -- or None if those are not supported.
     const MUT_STATIC_KIND: Option<Self::MemoryKinds>;
 
+    /// Whether to attempt to detect infinite loops (any kind of infinite
+    /// execution, really).
+    const DETECT_LOOPS: bool;
+
     /// Entry point to all function calls.
     ///
     /// Returns either the mir to use for the call, or `None` if execution should
index d01593ca5e91c6a1878d23892a7cff56708b34a3..64e0aeaaab7f042249f2717a6794a3ae91e0364f 100644 (file)
@@ -13,6 +13,7 @@
 //! All high-level functions to write to memory work on places as destinations.
 
 use std::convert::TryFrom;
+use std::mem;
 
 use rustc::ich::StableHashingContext;
 use rustc::mir;
@@ -57,11 +58,13 @@ pub enum Place<Id=AllocId> {
     },
 }
 
+// Can't use the macro here because that does not support named enum fields.
 impl<'a> HashStable<StableHashingContext<'a>> for Place {
     fn hash_stable<W: StableHasherResult>(
         &self, hcx: &mut StableHashingContext<'a>,
-        hasher: &mut StableHasher<W>) {
-
+        hasher: &mut StableHasher<W>)
+    {
+        mem::discriminant(self).hash_stable(hcx, hasher);
         match self {
             Place::Ptr(mem_place) => mem_place.hash_stable(hcx, hasher),
 
index 8aa053baae9f017afd022673b04bf5c5fe92d0c2..0e8466905eb767ccc54164dd35770dcfc937f265 100644 (file)
@@ -62,14 +62,13 @@ pub fn is_empty(&self) -> bool {
     pub fn observe_and_analyze(
         &mut self,
         tcx: &TyCtxt<'b, 'tcx, 'tcx>,
-        machine: &M,
         memory: &Memory<'a, 'mir, 'tcx, M>,
         stack: &[Frame<'mir, 'tcx>],
     ) -> EvalResult<'tcx, ()> {
 
         let mut hcx = tcx.get_stable_hashing_context();
         let mut hasher = StableHasher::<u64>::new();
-        (machine, stack).hash_stable(&mut hcx, &mut hasher);
+        stack.hash_stable(&mut hcx, &mut hasher);
         let hash = hasher.finish();
 
         if self.hashes.insert(hash) {
@@ -79,7 +78,7 @@ pub fn observe_and_analyze(
 
         info!("snapshotting the state of the interpreter");
 
-        if self.snapshots.insert(EvalSnapshot::new(machine, memory, stack)) {
+        if self.snapshots.insert(EvalSnapshot::new(memory, stack)) {
             // Spurious collision or first cycle
             return Ok(())
         }
@@ -345,7 +344,6 @@ fn resolve(&'b self, id: &AllocId) -> Option<&'b Allocation> {
 
 /// The virtual machine state during const-evaluation at a given point in time.
 struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
-    machine: M,
     memory: Memory<'a, 'mir, 'tcx, M>,
     stack: Vec<Frame<'mir, 'tcx>>,
 }
@@ -354,21 +352,20 @@ impl<'a, 'mir, 'tcx, M> EvalSnapshot<'a, 'mir, 'tcx, M>
     where M: Machine<'mir, 'tcx>,
 {
     fn new(
-        machine: &M,
         memory: &Memory<'a, 'mir, 'tcx, M>,
-        stack: &[Frame<'mir, 'tcx>]) -> Self {
-
+        stack: &[Frame<'mir, 'tcx>]
+    ) -> Self {
         EvalSnapshot {
-            machine: machine.clone(),
             memory: memory.clone(),
             stack: stack.into(),
         }
     }
 
     fn snapshot<'b: 'a>(&'b self)
-        -> (&'b M, MemorySnapshot<'b, 'mir, 'tcx, M>, Vec<FrameSnapshot<'a, 'tcx>>) {
-        let EvalSnapshot{ machine, memory, stack } = self;
-        (&machine, memory.snapshot(), stack.iter().map(|frame| frame.snapshot(memory)).collect())
+        -> (MemorySnapshot<'b, 'mir, 'tcx, M>, Vec<FrameSnapshot<'a, 'tcx>>)
+    {
+        let EvalSnapshot{ memory, stack } = self;
+        (memory.snapshot(), stack.iter().map(|frame| frame.snapshot(memory)).collect())
     }
 }
 
@@ -384,6 +381,8 @@ fn hash<H: Hasher>(&self, state: &mut H) {
     }
 }
 
+// Not using the macro because we need special handling for `memory`, which the macro
+// does not support at the same time as the extra bounds on the type.
 impl<'a, 'b, 'mir, 'tcx, M> HashStable<StableHashingContext<'b>>
     for EvalSnapshot<'a, 'mir, 'tcx, M>
     where M: Machine<'mir, 'tcx>,
@@ -391,10 +390,10 @@ impl<'a, 'b, 'mir, 'tcx, M> HashStable<StableHashingContext<'b>>
     fn hash_stable<W: StableHasherResult>(
         &self,
         hcx: &mut StableHashingContext<'b>,
-        hasher: &mut StableHasher<W>) {
-
-        let EvalSnapshot{ machine, memory, stack } = self;
-        (machine, &memory.data, stack).hash_stable(hcx, hasher);
+        hasher: &mut StableHasher<W>)
+    {
+        let EvalSnapshot{ memory: _, stack } = self;
+        stack.hash_stable(hcx, hasher);
     }
 }
 
index 545333e8791760fd29306e59154c4e51b972d271..2835a46e7662d4674979b74694bcfa6ae1e47c83 100644 (file)
@@ -65,6 +65,10 @@ pub fn inc_step_counter_and_detect_loops(&mut self) -> EvalResult<'tcx, ()> {
             }
         }
 
+        if !M::DETECT_LOOPS {
+            return Ok(());
+        }
+
         if self.loop_detector.is_empty() {
             // First run of the loop detector
 
@@ -75,7 +79,6 @@ pub fn inc_step_counter_and_detect_loops(&mut self) -> EvalResult<'tcx, ()> {
 
         self.loop_detector.observe_and_analyze(
             &self.tcx,
-            &self.machine,
             &self.memory,
             &self.stack[..],
         )