about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2018-04-02 00:14:44 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2018-04-02 00:14:44 +0300
commit8f9ec1cb06524a483b1bfc81c9912ebb7d46cb52 (patch)
tree5d203672e9f813655bc05f1fa57193c35a15b9c0
parentd2235f20b5295394450f4962fb5f93254e63640c (diff)
downloadrust-8f9ec1cb06524a483b1bfc81c9912ebb7d46cb52.tar.gz
rust-8f9ec1cb06524a483b1bfc81c9912ebb7d46cb52.zip
avoid IdxSets containing garbage above the universe length
This makes sure that all bits in each IdxSet between the universe length
and the end of the word are all zero instead of being in an indeterminate state.

This fixes a crash with RUST_LOG=rustc_mir, and is probably a good idea
anyway.
-rw-r--r--src/librustc_data_structures/indexed_set.rs74
-rw-r--r--src/librustc_mir/dataflow/impls/mod.rs4
2 files changed, 75 insertions, 3 deletions
diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs
index 7ab6a269148..c9495587c46 100644
--- a/src/librustc_data_structures/indexed_set.rs
+++ b/src/librustc_data_structures/indexed_set.rs
@@ -121,7 +121,9 @@ impl<T: Idx> IdxSetBuf<T> {
 
     /// Creates set holding every element whose index falls in range 0..universe_size.
     pub fn new_filled(universe_size: usize) -> Self {
-        Self::new(!0, universe_size)
+        let mut result = Self::new(!0, universe_size);
+        result.trim_to(universe_size);
+        result
     }
 
     /// Creates set holding no elements.
@@ -168,6 +170,36 @@ impl<T: Idx> IdxSet<T> {
         }
     }
 
+    /// Sets all elements up to `universe_size`
+    pub fn set_up_to(&mut self, universe_size: usize) {
+        for b in &mut self.bits {
+            *b = !0;
+        }
+        self.trim_to(universe_size);
+    }
+
+    /// Clear all elements above `universe_size`.
+    fn trim_to(&mut self, universe_size: usize) {
+        let word_bits = mem::size_of::<Word>() * 8;
+
+        // `trim_block` is the first block where some bits have
+        // to be cleared.
+        let trim_block = universe_size / word_bits;
+
+        // all the blocks above it have to be completely cleared.
+        if trim_block < self.bits.len() {
+            for b in &mut self.bits[trim_block+1..] {
+                *b = 0;
+            }
+
+            // at that block, the `universe_size % word_bits` lsbs
+            // should remain.
+            let remaining_bits = universe_size % word_bits;
+            let mask = (1<<remaining_bits)-1;
+            self.bits[trim_block] &= mask;
+        }
+    }
+
     /// Removes `elem` from the set `self`; returns true iff this changed `self`.
     pub fn remove(&mut self, elem: &T) -> bool {
         self.bits.clear_bit(elem.index())
@@ -252,3 +284,43 @@ impl<'a, T: Idx> Iterator for Iter<'a, T> {
         }
     }
 }
+
+#[test]
+fn test_trim_to() {
+    use std::cmp;
+
+    for i in 0..256 {
+        let mut idx_buf: IdxSetBuf<usize> = IdxSetBuf::new_filled(128);
+        idx_buf.trim_to(i);
+
+        let elems: Vec<usize> = idx_buf.iter().collect();
+        let expected: Vec<usize> = (0..cmp::min(i, 128)).collect();
+        assert_eq!(elems, expected);
+    }
+}
+
+#[test]
+fn test_set_up_to() {
+    for i in 0..128 {
+        for mut idx_buf in
+            vec![IdxSetBuf::new_empty(128), IdxSetBuf::new_filled(128)]
+            .into_iter()
+        {
+            idx_buf.set_up_to(i);
+
+            let elems: Vec<usize> = idx_buf.iter().collect();
+            let expected: Vec<usize> = (0..i).collect();
+            assert_eq!(elems, expected);
+        }
+    }
+}
+
+#[test]
+fn test_new_filled() {
+    for i in 0..128 {
+        let mut idx_buf = IdxSetBuf::new_filled(i);
+        let elems: Vec<usize> = idx_buf.iter().collect();
+        let expected: Vec<usize> = (0..i).collect();
+        assert_eq!(elems, expected);
+    }
+}
diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs
index c5f5492cd2c..287640439c0 100644
--- a/src/librustc_mir/dataflow/impls/mod.rs
+++ b/src/librustc_mir/dataflow/impls/mod.rs
@@ -389,7 +389,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedPlaces<'a, 'gcx, 'tcx>
     // sets on_entry bits for Arg places
     fn start_block_effect(&self, entry_set: &mut IdxSet<MovePathIndex>) {
         // set all bits to 1 (uninit) before gathering counterevidence
-        for e in entry_set.words_mut() { *e = !0; }
+        entry_set.set_up_to(self.bits_per_block());
 
         drop_flag_effects_for_function_entry(
             self.tcx, self.mir, self.mdpe,
@@ -443,7 +443,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedPlaces<'a, 'gcx, 'tc
 
     // sets on_entry bits for Arg places
     fn start_block_effect(&self, entry_set: &mut IdxSet<MovePathIndex>) {
-        for e in entry_set.words_mut() { *e = 0; }
+        entry_set.clear();
 
         drop_flag_effects_for_function_entry(
             self.tcx, self.mir, self.mdpe,