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.
This commit is contained in:
Ariel Ben-Yehuda 2018-04-02 00:14:44 +03:00
parent d2235f20b5
commit 8f9ec1cb06
2 changed files with 75 additions and 3 deletions

View File

@ -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);
}
}

View File

@ -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,