Skip to content

Commit

Permalink
-Zmiri-permissive-provenance and SB wildcard tags
Browse files Browse the repository at this point in the history
  • Loading branch information
carbotaniuman committed Apr 9, 2022
1 parent a25b65e commit ad59f75
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 44 deletions.
5 changes: 5 additions & 0 deletions src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ fn main() {
miri_config.tag_raw = true;
miri_config.check_number_validity = true;
}
"-Zmiri-permissive-provenance" => {
miri_config.permissive_provenance = true;
miri_config.tag_raw = true;
miri_config.check_number_validity = true;
}
"-Zmiri-track-raw-pointers" => {
eprintln!(
"WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated."
Expand Down
4 changes: 4 additions & 0 deletions src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ pub struct MiriConfig {
pub panic_on_unsupported: bool,
/// Which style to use for printing backtraces.
pub backtrace_style: BacktraceStyle,
/// Whether to enforce "permissive provenance" rules. Enabling this means int2ptr casts return
/// pointers with union provenance of all exposed pointers (and SB tags, if enabled).
pub permissive_provenance: bool,
/// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return
/// pointers with an invalid provenance, i.e., not valid for any memory access.
pub strict_provenance: bool,
Expand Down Expand Up @@ -140,6 +143,7 @@ impl Default for MiriConfig {
measureme_out: None,
panic_on_unsupported: false,
backtrace_style: BacktraceStyle::Short,
permissive_provenance: false,
strict_provenance: false,
}
}
Expand Down
35 changes: 23 additions & 12 deletions src/intptrcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ pub struct GlobalStateInner {
/// This is used as a memory address when a new pointer is casted to an integer. It
/// is always larger than any address that was previously made part of a block.
next_base_addr: u64,
/// Whether to enforce "permissive provenance" rules. Enabling this means int2ptr casts return
/// pointers with union provenance of all exposed pointers (and SB tags, if enabled).
permissive_provenance: bool,
/// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return
/// pointers with an invalid provenance, i.e., not valid for any memory access.
strict_provenance: bool,
Expand All @@ -39,6 +42,7 @@ impl GlobalStateInner {
base_addr: FxHashMap::default(),
exposed: FxHashSet::default(),
next_base_addr: STACK_ADDR,
permissive_provenance: config.permissive_provenance,
strict_provenance: config.strict_provenance,
}
}
Expand All @@ -47,7 +51,7 @@ impl GlobalStateInner {
impl<'mir, 'tcx> GlobalStateInner {
// Returns the `AllocId` that corresponds to the specified addr,
// or `None` if the addr is out of bounds
fn alloc_id_from_addr(addr: u64, ecx: &MiriEvalContext<'mir, 'tcx>) -> Option<AllocId> {
fn alloc_id_from_addr(ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64) -> Option<AllocId> {
let global_state = ecx.machine.intptrcast.borrow();

if addr == 0 {
Expand All @@ -60,7 +64,7 @@ impl<'mir, 'tcx> GlobalStateInner {
Ok(pos) => {
let (_, alloc_id) = global_state.int_to_ptr_map[pos];

if global_state.exposed.contains(&alloc_id) {
if !global_state.permissive_provenance || global_state.exposed.contains(&alloc_id) {
Some(global_state.int_to_ptr_map[pos].1)
} else {
None
Expand All @@ -75,7 +79,7 @@ impl<'mir, 'tcx> GlobalStateInner {
let offset = addr - glb;
// If the offset exceeds the size of the allocation, don't use this `alloc_id`.

if global_state.exposed.contains(&alloc_id)
if (!global_state.permissive_provenance || global_state.exposed.contains(&alloc_id))
&& offset
<= ecx
.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead)
Expand All @@ -91,13 +95,9 @@ impl<'mir, 'tcx> GlobalStateInner {
}
}

pub fn expose_addr(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer<Tag>) {
pub fn expose_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) {
let mut global_state = ecx.machine.intptrcast.borrow_mut();
let (tag, _) = ptr.into_parts();

if let machine::AllocType::Concrete(alloc_id) = tag.alloc_id {
global_state.exposed.insert(alloc_id);
}
global_state.exposed.insert(alloc_id);
}

pub fn abs_ptr_to_rel(
Expand All @@ -109,7 +109,7 @@ impl<'mir, 'tcx> GlobalStateInner {
let alloc_id = if let machine::AllocType::Concrete(alloc_id) = tag.alloc_id {
alloc_id
} else {
match GlobalStateInner::alloc_id_from_addr(addr.bytes(), ecx) {
match GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes()) {
Some(alloc_id) => alloc_id,
None => return None,
}
Expand All @@ -135,11 +135,22 @@ impl<'mir, 'tcx> GlobalStateInner {
return Pointer::new(None, Size::from_bytes(addr));
}

let alloc_id = GlobalStateInner::alloc_id_from_addr(addr, ecx);
let alloc_id = GlobalStateInner::alloc_id_from_addr(ecx, addr);

// Pointers created from integers are untagged.

let sb = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows {
if global_state.permissive_provenance {
stacked_borrows.borrow_mut().wildcard_tag()
} else {
SbTag::Untagged
}
} else {
SbTag::Untagged
};

Pointer::new(
alloc_id.map(|_| Tag { alloc_id: machine::AllocType::Casted, sb: SbTag::Untagged }),
alloc_id.map(|_| Tag { alloc_id: machine::AllocType::Casted, sb }),
Size::from_bytes(addr),
)
}
Expand Down
67 changes: 46 additions & 21 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,6 @@ impl Provenance for Tag {
/// Extra per-allocation data
#[derive(Debug, Clone)]
pub struct AllocExtra {
// TODO: this really doesn't need to be here,
// but we're forced to bodge it here for now
pub alloc_id: AllocId,
/// Stacked Borrows state is only added if it is enabled.
pub stacked_borrows: Option<stacked_borrows::AllocExtra>,
/// Data race detection via the use of a vector-clock,
Expand Down Expand Up @@ -579,7 +576,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
};
let alloc: Allocation<Tag, Self::AllocExtra> = alloc.convert_tag_add_extra(
&ecx.tcx,
AllocExtra { alloc_id: id, stacked_borrows: stacks, data_race: race_alloc },
AllocExtra { stacked_borrows: stacks, data_race: race_alloc },
|ptr| Evaluator::tag_alloc_base_pointer(ecx, ptr),
);
Cow::Owned(alloc)
Expand Down Expand Up @@ -611,15 +608,29 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {

/// Convert a pointer with provenance into an allocation-offset pair,
/// or a `None` with an absolute address if that conversion is not possible.
fn ptr_get_alloc(
fn ptr_reify_alloc(
ecx: &MiriEvalContext<'mir, 'tcx>,
ptr: Pointer<Self::PointerTag>,
) -> Option<(AllocId, Size)> {
intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr)
) -> Option<(AllocId, Size, Pointer<Self::PointerTag>)> {
let rel_ptr = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr);
rel_ptr.map(|(alloc_id, size)| {
let new_ptr =
ptr.map_provenance(|t| Tag { alloc_id: AllocType::Concrete(alloc_id), ..t });

(alloc_id, size, new_ptr)
})
}

fn expose_addr(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer<Self::PointerTag>) {
intptrcast::GlobalStateInner::expose_addr(ecx, ptr)
fn expose_ptr(ecx: &InterpCx<'mir, 'tcx, Self>, ptr: Pointer<Self::PointerTag>) {
let (tag, _) = ptr.into_parts();

if let AllocType::Concrete(alloc_id) = tag.alloc_id {
intptrcast::GlobalStateInner::expose_addr(ecx, alloc_id);

if let Some(stacked_borrows) = &ecx.machine.stacked_borrows {
stacked_borrows.borrow_mut().expose_ptr(tag.sb)
}
}
}

#[inline(always)]
Expand All @@ -630,12 +641,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
tag: Tag,
range: AllocRange,
) -> InterpResult<'tcx> {
let alloc_id = if let AllocType::Concrete(alloc_id) = tag.alloc_id {
alloc_id
} else {
bug!("`memory_read` called with non-concrete tag")
};

if let Some(data_race) = &alloc_extra.data_race {
data_race.read(alloc_extra.alloc_id, range, machine.data_race.as_ref().unwrap())?;
data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?;
}
if let Some(stacked_borrows) = &alloc_extra.stacked_borrows {
stacked_borrows.memory_read(
alloc_extra.alloc_id,
alloc_id,
tag.sb,
range,
machine.stacked_borrows.as_ref().unwrap(),
Expand All @@ -653,12 +670,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
tag: Tag,
range: AllocRange,
) -> InterpResult<'tcx> {
let alloc_id = if let AllocType::Concrete(alloc_id) = tag.alloc_id {
alloc_id
} else {
bug!("`memory_written` called with non-concrete tag")
};

if let Some(data_race) = &mut alloc_extra.data_race {
data_race.write(alloc_extra.alloc_id, range, machine.data_race.as_mut().unwrap())?;
data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?;
}
if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
stacked_borrows.memory_written(
alloc_extra.alloc_id,
alloc_id,
tag.sb,
range,
machine.stacked_borrows.as_mut().unwrap(),
Expand All @@ -676,19 +699,21 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
tag: Tag,
range: AllocRange,
) -> InterpResult<'tcx> {
if Some(alloc_extra.alloc_id) == machine.tracked_alloc_id {
register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_extra.alloc_id));
let alloc_id = if let AllocType::Concrete(alloc_id) = tag.alloc_id {
alloc_id
} else {
bug!("`memory_deallocated` called with non-concrete tag")
};

if Some(alloc_id) == machine.tracked_alloc_id {
register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id));
}
if let Some(data_race) = &mut alloc_extra.data_race {
data_race.deallocate(
alloc_extra.alloc_id,
range,
machine.data_race.as_mut().unwrap(),
)?;
data_race.deallocate(alloc_id, range, machine.data_race.as_mut().unwrap())?;
}
if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
stacked_borrows.memory_deallocated(
alloc_extra.alloc_id,
alloc_id,
tag.sb,
range,
machine.stacked_borrows.as_mut().unwrap(),
Expand Down
Loading

0 comments on commit ad59f75

Please sign in to comment.