properly prevent recursive statics from marking each other

This commit is contained in:
Oliver Schneider 2017-02-08 16:27:28 +01:00
parent e23fc79d25
commit 080d3e4355
3 changed files with 30 additions and 12 deletions

View File

@ -172,7 +172,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// FIXME: cache these allocs // FIXME: cache these allocs
let ptr = self.memory.allocate(s.len() as u64, 1)?; let ptr = self.memory.allocate(s.len() as u64, 1)?;
self.memory.write_bytes(ptr, s.as_bytes())?; self.memory.write_bytes(ptr, s.as_bytes())?;
self.memory.mark_static(ptr.alloc_id, false)?; self.memory.mark_static_initalized(ptr.alloc_id, false)?;
Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128))) Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128)))
} }
@ -194,9 +194,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Str(ref s) => return self.str_to_value(s), Str(ref s) => return self.str_to_value(s),
ByteStr(ref bs) => { ByteStr(ref bs) => {
// FIXME: cache these allocs
let ptr = self.memory.allocate(bs.len() as u64, 1)?; let ptr = self.memory.allocate(bs.len() as u64, 1)?;
self.memory.write_bytes(ptr, bs)?; self.memory.write_bytes(ptr, bs)?;
self.memory.mark_static(ptr.alloc_id, false)?; self.memory.mark_static_initalized(ptr.alloc_id, false)?;
PrimVal::Ptr(ptr) PrimVal::Ptr(ptr)
} }
@ -316,16 +317,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let global_value = self.globals.get_mut(&id) let global_value = self.globals.get_mut(&id)
.expect("global should have been cached (static)"); .expect("global should have been cached (static)");
match global_value.value { match global_value.value {
Value::ByRef(ptr) => self.memory.mark_static(ptr.alloc_id, mutable)?, Value::ByRef(ptr) => self.memory.mark_static_initalized(ptr.alloc_id, mutable)?,
Value::ByVal(val) => if let PrimVal::Ptr(ptr) = val { Value::ByVal(val) => if let PrimVal::Ptr(ptr) = val {
self.memory.mark_static(ptr.alloc_id, mutable)?; self.memory.mark_static_initalized(ptr.alloc_id, mutable)?;
}, },
Value::ByValPair(val1, val2) => { Value::ByValPair(val1, val2) => {
if let PrimVal::Ptr(ptr) = val1 { if let PrimVal::Ptr(ptr) = val1 {
self.memory.mark_static(ptr.alloc_id, mutable)?; self.memory.mark_static_initalized(ptr.alloc_id, mutable)?;
} }
if let PrimVal::Ptr(ptr) = val2 { if let PrimVal::Ptr(ptr) = val2 {
self.memory.mark_static(ptr.alloc_id, mutable)?; self.memory.mark_static_initalized(ptr.alloc_id, mutable)?;
} }
}, },
} }
@ -870,10 +871,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Value::ByRef(ptr) => Lvalue::from_ptr(ptr), Value::ByRef(ptr) => Lvalue::from_ptr(ptr),
_ => { _ => {
let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.substs)?; let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.substs)?;
self.memory.mark_static(ptr.alloc_id);
self.write_value_to_ptr(global_val.value, ptr, global_val.ty)?; self.write_value_to_ptr(global_val.value, ptr, global_val.ty)?;
// see comment on `initialized` field // see comment on `initialized` field
if global_val.initialized { if global_val.initialized {
self.memory.mark_static(ptr.alloc_id, global_val.mutable)?; self.memory.mark_static_initalized(ptr.alloc_id, global_val.mutable)?;
} }
let lval = self.globals.get_mut(&cid).expect("already checked"); let lval = self.globals.get_mut(&cid).expect("already checked");
*lval = Global { *lval = Global {

View File

@ -38,7 +38,7 @@ pub struct Allocation {
/// The alignment of the allocation to detect unaligned reads. /// The alignment of the allocation to detect unaligned reads.
pub align: u64, pub align: u64,
/// Whether the allocation may be modified. /// Whether the allocation may be modified.
/// Use the `mark_static` method of `Memory` to ensure that an error occurs, if the memory of this /// Use the `mark_static_initalized` method of `Memory` to ensure that an error occurs, if the memory of this
/// allocation is modified or deallocated in the future. /// allocation is modified or deallocated in the future.
pub static_kind: StaticKind, pub static_kind: StaticKind,
} }
@ -152,6 +152,11 @@ impl<'tcx> Function<'tcx> {
pub struct Memory<'a, 'tcx> { pub struct Memory<'a, 'tcx> {
/// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations) /// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations)
alloc_map: HashMap<AllocId, Allocation>, alloc_map: HashMap<AllocId, Allocation>,
/// Set of statics, constants, promoteds, vtables, ... to prevent `mark_static_initalized` from stepping
/// out of its own allocations.
/// This set only contains statics backed by an allocation. If they are ByVal or ByValPair they
/// are not here, but will be inserted once they become ByRef.
static_alloc: HashSet<AllocId>,
/// Number of virtual bytes allocated /// Number of virtual bytes allocated
memory_usage: u64, memory_usage: u64,
/// Maximum number of virtual bytes that may be allocated /// Maximum number of virtual bytes that may be allocated
@ -189,6 +194,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
memory_size: max_memory, memory_size: max_memory,
memory_usage: 0, memory_usage: 0,
packed: BTreeSet::new(), packed: BTreeSet::new(),
static_alloc: HashSet::new(),
} }
} }
@ -624,8 +630,15 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
/// Reading and writing /// Reading and writing
impl<'a, 'tcx> Memory<'a, 'tcx> { impl<'a, 'tcx> Memory<'a, 'tcx> {
/// mark an allocation as static, either mutable or not /// mark an allocation as being the entry point to a static (see `static_alloc` field)
pub fn mark_static(&mut self, alloc_id: AllocId, mutable: bool) -> EvalResult<'tcx> { pub fn mark_static(&mut self, alloc_id: AllocId) {
if !self.static_alloc.insert(alloc_id) {
bug!("tried to mark an allocation ({:?}) as static twice", alloc_id);
}
}
/// mark an allocation as static and initialized, either mutable or not
pub fn mark_static_initalized(&mut self, alloc_id: AllocId, mutable: bool) -> EvalResult<'tcx> {
// do not use `self.get_mut(alloc_id)` here, because we might have already marked a // do not use `self.get_mut(alloc_id)` here, because we might have already marked a
// sub-element or have circular pointers (e.g. `Rc`-cycles) // sub-element or have circular pointers (e.g. `Rc`-cycles)
let relocations = match self.alloc_map.get_mut(&alloc_id) { let relocations = match self.alloc_map.get_mut(&alloc_id) {
@ -645,7 +658,10 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
}; };
// recurse into inner allocations // recurse into inner allocations
for &alloc in relocations.values() { for &alloc in relocations.values() {
self.mark_static(alloc, mutable)?; // relocations into other statics are not "inner allocations"
if !self.static_alloc.contains(&alloc) {
self.mark_static_initalized(alloc, mutable)?;
}
} }
// put back the relocations // put back the relocations
self.alloc_map.get_mut(&alloc_id).expect("checked above").relocations = relocations; self.alloc_map.get_mut(&alloc_id).expect("checked above").relocations = relocations;

View File

@ -112,7 +112,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
} }
} }
self.memory.mark_static(vtable.alloc_id, false)?; self.memory.mark_static_initalized(vtable.alloc_id, false)?;
Ok(vtable) Ok(vtable)
} }