diff options
| author | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2018-04-02 00:14:44 +0300 |
|---|---|---|
| committer | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2018-04-02 00:14:44 +0300 |
| commit | 8f9ec1cb06524a483b1bfc81c9912ebb7d46cb52 (patch) | |
| tree | 5d203672e9f813655bc05f1fa57193c35a15b9c0 | |
| parent | d2235f20b5295394450f4962fb5f93254e63640c (diff) | |
| download | rust-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.rs | 74 | ||||
| -rw-r--r-- | src/librustc_mir/dataflow/impls/mod.rs | 4 |
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, |
