-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add misc debugging helpers and feature to poison dead memory #1241
base: master
Are you sure you want to change the base?
Changes from 6 commits
d58d7a7
8dff03c
6023bb7
7f2b2c6
eebe06e
6d3b1e0
655e5bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -248,8 +248,13 @@ impl Block { | |
holes += 1; | ||
} | ||
|
||
#[cfg(feature = "immix_zero_on_release")] | ||
crate::util::memory::zero(line.start(), Line::BYTES); | ||
// Cheeky trick to encode the released line into the poisoned value | ||
#[cfg(feature = "poison_on_release")] | ||
crate::util::memory::set_pattern( | ||
line.start(), | ||
(0xdeadbeef ^ line.start().as_usize()) & !0xff, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why poison as a pattern rather than a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This removes the existing code for You should have an assertion to make sure that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feature supersedes zero on release. The pattern here is helpful since it encodes the line that was released into the pattern. So you can XOR with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you think "poison_on_release" is better than "zero_on_release", just remove the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I am not following here. Can you get the line by aligning down from the faulty address? Why is XOR needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem isn't the line itself but what object was referring to it. In my case I did not have a debugger available because crashes were happening at Android boot time. So I had to be creative to debug memory corruption errors (hence the So consider the case that a line has been overwritten when an object inside it was live. Object = An object referring to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is I guess unnecessary in the general case if you have a debugger, but I definitely found it useful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Without the explanation above, I wouldn't know why you encode the value in that way, and how I am supposed to use the encoded value. Those explanation should go into the comments and the docs in the code so others won't have the same question as I did when they encounter the code and when they use this feature. Besides, I suggest separating it into a different features:
|
||
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")] | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -105,6 +105,48 @@ 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) { | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest using a fixed-size integer type (or a type trait) for the pattern. At the call site, we give the pattern as a hexadecimal literal, but here we write memory at the granularity of
Suggested change
Alternatively
Suggested change
|
||||||||||||||||||||||
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. | ||||||||||||||||||||||
/// | ||||||||||||||||||||||
/// # Safety | ||||||||||||||||||||||
/// Extremely unsafe for arbitrary addresses since they may not have been mapped. Only use | ||||||||||||||||||||||
/// this function for locations that are KNOWN to be broken AND allocated by MMTk. | ||||||||||||||||||||||
pub unsafe 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 { | ||||||||||||||||||||||
if current == addr.to_ptr::<usize>() { | ||||||||||||||||||||||
string.push_str(" | "); | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
string.push(' '); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
let s = 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 | ||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using an arbitrary value, you can define a mapping between space and its poison value, or use something from the space (such as the SpaceDescriptor index, or the space name).
I would suggest creating a module
crate::util::poison_on_release
. Define the poison values there, and define functions to poison a memory region.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if we need the different values to tell which space it is, especially after Kunshan's change in #1236. But if we do want to use different values, there needs to be a place where we can look at and know what the value means.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well that might be true. It was helpful to me but that predates when I was using
prctl
. I can remove it and replace it with a static pattern of0xab
or something obviously nonsense.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The annotation of #1236 is precise for Map64, but imprecise for Map32 due to chunk reuse between spaces. It is still helpful to let each space have a different poison value.