about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan MacKenzie <ecstaticmorse@gmail.com>2018-06-26 21:59:43 -0700
committerDylan MacKenzie <ecstaticmorse@gmail.com>2018-07-04 14:36:07 -0700
commitb3b04b8cc6fb66b89613b4b636182b5de53a0601 (patch)
treec0d8c27d2099e210a6f487ce63e0cb2051247139
parent647ba29b90155e07cf569060d344242b3ee474eb (diff)
downloadrust-b3b04b8cc6fb66b89613b4b636182b5de53a0601.tar.gz
rust-b3b04b8cc6fb66b89613b4b636182b5de53a0601.zip
Avoid overflow in step counter
This removes the `usize` argument to `inc_step_counter`. Now, the step
counter increments by exactly one for every terminator evaluated. After
`STEPS_UNTIL_DETECTOR_ENABLED` steps elapse, the detector is run every
`DETECTOR_SNAPSHOT_PERIOD` steps. The step counter is only kept modulo
this period.
-rw-r--r--src/librustc_mir/interpret/eval_context.rs27
-rw-r--r--src/librustc_mir/interpret/step.rs26
2 files changed, 27 insertions, 26 deletions
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 020abbf94c5..363ad537b3f 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -43,9 +43,11 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
     /// The maximum number of stack frames allowed
     pub(crate) stack_limit: usize,
 
-    /// The number of terminators to be evaluated before enabling the infinite
-    /// loop detector.
-    pub(crate) steps_until_detector_enabled: isize,
+    /// When this value is negative, it indicates the number of interpreter
+    /// steps *until* the loop detector is enabled. When it is positive, it is
+    /// the number of steps after the detector has been enabled modulo the loop
+    /// detector period.
+    pub(crate) steps_since_detector_enabled: isize,
 
     pub(crate) loop_detector: InfiniteLoopDetector<'a, 'mir, 'tcx, M>,
 }
@@ -148,14 +150,15 @@ type EvalSnapshot<'a, 'mir, 'tcx, M>
 pub(crate) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
     /// The set of all `EvalSnapshot` *hashes* observed by this detector.
     ///
-    /// When a collision occurs in this table, we store the full snapshot in `snapshots`.
+    /// When a collision occurs in this table, we store the full snapshot in
+    /// `snapshots`.
     hashes: FxHashSet<u64>,
 
     /// The set of all `EvalSnapshot`s observed by this detector.
     ///
-    /// An `EvalSnapshot` will only be fully cloned once it has caused a collision in `hashes`. As
-    /// a result, the detector must observe at least *two* full cycles of an infinite loop before
-    /// it triggers.
+    /// An `EvalSnapshot` will only be fully cloned once it has caused a
+    /// collision in `hashes`. As a result, the detector must observe at least
+    /// *two* full cycles of an infinite loop before it triggers.
     snapshots: FxHashSet<EvalSnapshot<'a, 'mir, 'tcx, M>>,
 }
 
@@ -291,7 +294,7 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf
     }
 }
 
-const MAX_TERMINATORS: isize = 1_000_000;
+const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000;
 
 impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     pub fn new(
@@ -310,16 +313,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
             stack: Vec::new(),
             stack_limit: tcx.sess.const_eval_stack_frame_limit,
             loop_detector: Default::default(),
-            steps_until_detector_enabled: MAX_TERMINATORS,
+            steps_since_detector_enabled: -STEPS_UNTIL_DETECTOR_ENABLED,
         }
     }
 
     pub(crate) fn with_fresh_body<F: FnOnce(&mut Self) -> R, R>(&mut self, f: F) -> R {
         let stack = mem::replace(&mut self.stack, Vec::new());
-        let steps = mem::replace(&mut self.steps_until_detector_enabled, MAX_TERMINATORS);
+        let steps = mem::replace(&mut self.steps_since_detector_enabled, -STEPS_UNTIL_DETECTOR_ENABLED);
         let r = f(self);
         self.stack = stack;
-        self.steps_until_detector_enabled = steps;
+        self.steps_since_detector_enabled = steps;
         r
     }
 
@@ -661,8 +664,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
             }
 
             Aggregate(ref kind, ref operands) => {
-                self.inc_step_counter_and_detect_loops(operands.len())?;
-
                 let (dest, active_field_index) = match **kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
                         self.write_discriminant_value(dest_ty, dest, variant_index)?;
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 2025db48718..25f45fff04d 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -12,23 +12,23 @@ use super::{EvalContext, Machine};
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     where M: Clone + Eq + Hash,
 {
-    /// Returns `true` if the loop detector should take a snapshot during the current step.
-    pub fn is_loop_detector_scheduled(&self) -> bool {
+    pub fn inc_step_counter_and_detect_loops(&mut self) -> EvalResult<'tcx, ()> {
         /// The number of steps between loop detector snapshots.
         /// Should be a power of two for performance reasons.
-        const DETECTOR_SNAPSHOT_PERIOD: isize = 1 << 8;
+        const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
 
-        let steps = self.steps_until_detector_enabled;
-        steps <= 0 && steps % DETECTOR_SNAPSHOT_PERIOD == 0
-    }
+        {
+            let steps = &mut self.steps_since_detector_enabled;
 
-    pub fn inc_step_counter_and_detect_loops(&mut self, n: usize) -> EvalResult<'tcx, ()> {
-        // TODO: Remove `as` cast
-        self.steps_until_detector_enabled =
-            self.steps_until_detector_enabled.saturating_sub(n as isize);
+            *steps += 1;
+            if *steps < 0 {
+                return Ok(());
+            }
 
-        if !self.is_loop_detector_scheduled() {
-            return Ok(());
+            *steps %= DETECTOR_SNAPSHOT_PERIOD;
+            if *steps != 0 {
+                return Ok(());
+            }
         }
 
         if self.loop_detector.is_empty() {
@@ -61,7 +61,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
             return Ok(true);
         }
 
-        self.inc_step_counter_and_detect_loops(1)?;
+        self.inc_step_counter_and_detect_loops()?;
 
         let terminator = basic_block.terminator();
         assert_eq!(old_frames, self.cur_frame());