Skip to content

Commit

Permalink
Add misc debugging helpers and feature to poison dead memory
Browse files Browse the repository at this point in the history
We add some misc debugging helpers to help binding implementers in
debugging tricky memory corruption bugs. We now can also poison dead
memory in each space's `release` method. This feature supersedes
"immix_zero_on_release".
  • Loading branch information
k-sareen committed Nov 28, 2024
1 parent 8640ab8 commit d58d7a7
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/policy/copyspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ impl<VM: VMBinding> CopySpace<VM> {
}

pub fn release(&self) {
#[cfg(feature = "poison_on_release")]
for (start, size) in self.pr.iterate_allocated_regions() {
crate::util::memory::set(start, 0xbc, size);
}

for (start, size) in self.pr.iterate_allocated_regions() {
// Clear the forwarding bits if it is on the side.
if let MetadataSpec::OnSide(side_forwarding_status_table) =
Expand Down
4 changes: 2 additions & 2 deletions src/policy/immix/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ impl Block {
holes += 1;
}

#[cfg(feature = "immix_zero_on_release")]
crate::util::memory::zero(line.start(), Line::BYTES);
#[cfg(feature = "poison_on_release")]
crate::util::memory::set_pattern(line.start(), (0xdeadbeef ^ line.start().as_usize()) & !0xff, Line::BYTES);

// We need to clear the pin bit if it is on the side, as this line can be reused
#[cfg(feature = "object_pinning")]
Expand Down
9 changes: 8 additions & 1 deletion src/policy/largeobjectspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,15 @@ impl<VM: VMBinding> LargeObjectSpace<VM> {
let sweep = |object: ObjectReference| {
#[cfg(feature = "vo_bit")]
crate::util::metadata::vo_bit::unset_vo_bit(object);
if self.common.needs_log_bit {
VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC
.clear::<VM>(object, Ordering::SeqCst);
}
let start = object.to_object_start::<VM>();
#[cfg(feature = "poison_on_release")]
crate::util::memory::set(start, 0xed, VM::VMObjectModel::get_current_size(object));
self.pr
.release_pages(get_super_page(object.to_object_start::<VM>()));
.release_pages(get_super_page(start));
};
if sweep_nursery {
for object in self.treadmill.collect_nursery() {
Expand Down
24 changes: 24 additions & 0 deletions src/scheduler/gc_work.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,12 @@ impl<E: ProcessEdgesWork> ObjectTracer for ProcessEdgesWorkTracer<E> {
/// Forward the `trace_object` call to the underlying `ProcessEdgesWork`,
/// and flush as soon as the underlying buffer of `process_edges_work` is full.
fn trace_object(&mut self, object: ObjectReference) -> ObjectReference {
debug_assert!(!object.is_null());
debug_assert!(
<E::VM as VMBinding>::VMObjectModel::is_object_sane(object),
"Object {:?} is not sane!",
object,
);
let result = self.process_edges_work.trace_object(object);
self.flush_if_full();
result
Expand Down Expand Up @@ -693,6 +699,13 @@ impl<VM: VMBinding> ProcessEdgesWork for SFTProcessEdges<VM> {
fn trace_object(&mut self, object: ObjectReference) -> ObjectReference {
use crate::policy::sft::GCWorkerMutRef;

debug_assert!(!object.is_null());
debug_assert!(
<VM as VMBinding>::VMObjectModel::is_object_sane(object),
"Object {:?} is not sane!",
object,
);

// Erase <VM> type parameter
let worker = GCWorkerMutRef::new(self.worker());

Expand Down Expand Up @@ -840,6 +853,11 @@ pub trait ScanObjectsWork<VM: VMBinding>: GCWork<VM> + Sized {

if <VM as VMBinding>::VMScanning::support_slot_enqueuing(tls, object) {
trace!("Scan object (slot) {}", object);
debug_assert!(
<VM as VMBinding>::VMObjectModel::is_object_sane(object),
"Object {:?} is not sane!",
object,
);
// If an object supports slot-enqueuing, we enqueue its slots.
<VM as VMBinding>::VMScanning::scan_object(tls, object, &mut closure);
self.post_scan_object(object);
Expand Down Expand Up @@ -977,6 +995,12 @@ impl<VM: VMBinding, P: PlanTraceObject<VM> + Plan<VM = VM>, const KIND: TraceKin
// Skip slots that are not holding an object reference.
return;
};
debug_assert!(
<VM as VMBinding>::VMObjectModel::is_object_sane(object),
"Object {:?} from slot {:?} is not sane!",
object,
slot,
);
let new_object = self.trace_object(object);
if P::may_move_objects::<KIND>() && new_object != object {
slot.store(new_object);
Expand Down
40 changes: 40 additions & 0 deletions src/util/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,46 @@ pub fn set(start: Address, val: u8, len: usize) {
}
}

/// Set a range of memory to the given pattern. Similar to C++'s std::fill.
pub fn set_pattern(start: Address, pattern: usize, len: usize) {
debug_assert!(std::mem::size_of::<usize>() <= len);
debug_assert!(len % std::mem::size_of::<usize>() == 0);

let end_addr = (start + len).to_mut_ptr::<usize>();
let mut current = start.to_mut_ptr::<usize>();
while current < end_addr {
unsafe {
*current = pattern;
current = current.add(1);
}
}
}

/// Dump RAM around a given address. Note that be careful when using this function as it may
/// segfault for unmapped memory. ONLY use it for locations that are KNOWN to be broken AND
/// allocated by MMTk.
pub fn dump_ram_around_address(addr: Address, bytes: usize) -> String {
let mut string: String = String::new();
let end_addr = (addr + bytes).to_ptr::<usize>();
let mut current = (addr - bytes).to_ptr::<usize>();
while current < end_addr {
unsafe {
if current == addr.to_ptr::<usize>() {
string.push_str(" | ");
} else {
string.push_str(" ");
}
let s = unsafe { current.read() };
#[cfg(target_pointer_width = "64")]
string.push_str(format!("{:#018x}", s).as_str());
#[cfg(target_pointer_width = "32")]
string.push_str(format!("{:#010x}", s).as_str());
current = current.add(1);
}
}
string
}

/// Demand-zero mmap:
/// This function mmaps the memory and guarantees to zero all mapped memory.
/// This function WILL overwrite existing memory mapping. The user of this function
Expand Down

0 comments on commit d58d7a7

Please sign in to comment.