-
Notifications
You must be signed in to change notification settings - Fork 27
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
mmap-alloc: Improve tests for permissions, fix realloc bugs #87
Conversation
@Dr-Emann Just wanted to give you a heads up about this - I came across a line about Linux guaranteeing non-null addresses from I will say that I'm not 100% convinced about the manpage being correct - both @ezrosent and I have recollections (mine in the form of a comment in UPDATE: it's definitely guaranteed on Mac. I'm still trying to determine whether |
09e9ca2
to
bcd420c
Compare
Can I cast my vote against formatting multiline functions definitions this way? Besides my personal bias (I think it's incredibly ugly), it's no longer the recommended format for rust code, and using the newer rustfmt-nightly formats it much better (see also, the format button on the playground) |
As for mapping returning null: don't worry about it. It was fun figuring how to deal with it, even if it would never happen. fyi, I did mention that posix seemed to disallow returning null from mmap without MAP_FIXED in the description of my pull request. 😜 |
Oh, absolutely! I've been using stable rustfmt, but I'm happy to switch to rustfmt-nightly; I just didn't remember it was a thing so I never installed it.
Shit you're right - I see that now (and I think I know why I didn't catch it before). That's totally my bad. Your point in that original comment about explicitly mapping a null page is a good one! I think I'll add that point to my comment in this PR so if it becomes an issue in the future, we'll have a comment with an idea of how to fix it. EDIT: Actually, mapping the null page at the beginning wouldn't work - if it failed, that might be because somebody else had already mapped it. If that person later unmapped it, we'd still be at a risk of getting null pages back from |
OK, looks like we're good on Mac with respect to mapping the null page. |
bcd420c
to
b9c362c
Compare
mmap-alloc/src/lib.rs
Outdated
// we're configured to allocate un-readable or un-writable memory - we'll need to be | ||
// able to read/write in order to copy the data. | ||
protect(ptr, old_size, perms::PROT_READ); | ||
protect(new_ptr, new_size, perms::PROT_WRITE); |
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.
Even though reallocation should be infrequent, I'm not sure how I feel about 3 guaranteed syscalls, when in most cases none would be needed (I'd expect most allocators to expect read+write)
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.
Good call. I'll check the perms first.
mmap-alloc/src/tests.rs
Outdated
let output = Command::new("cat") | ||
.arg(format!("/proc/{}/maps", unsafe { libc::getpid() })) | ||
.output() | ||
.unwrap(); |
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.
Is there a reason to use cat vs opening the file ourselves with std::fs::File?
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.
This was adapted from an earlier version of the function whose job was to get the permissions for a particular address block, and thus was a more complicated command involving a full sequence of commands chained together with pipes. I honestly didn't even notice what this ended up getting whittled down to - I'll change it.
ac3c722
to
3e5636d
Compare
I've been so far unable to find documentation conclusively stating that |
@Dr-Emann, I'll let you weigh in first, but otherwise I'm ready to merge this. |
mmap-alloc/src/lib.rs
Outdated
return Ok(ptr); | ||
} | ||
} | ||
} |
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.
Since we're not overriding shrink_in_place for macos either, I don't think this makes sense to have. The cases which would be handled by the default implementation (and are handled for macos and windows) should already be handled by the old_size == new_size
check above, which checks if the old layout and the new layout both round up to the same size.
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.
Sorry, I hoped there would be more context in the preview. The block starts here
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 fixed this by implementing shrink_in_place
on Mac and simplifying the logic here. How does that look?
@@ -255,6 +231,9 @@ impl Default for MapAllocBuilder { | |||
pub struct MapAlloc { | |||
pagesize: usize, | |||
huge_pagesize: Option<usize>, | |||
#[cfg_attr(target_os = "linux", allow(unused))] read: bool, | |||
#[cfg_attr(target_os = "linux", allow(unused))] write: bool, | |||
#[cfg_attr(target_os = "linux", allow(unused))] exec: bool, |
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.
It seems unfortunate to have this duplication (the same info should be stored in the perms
field. Could we either:
- Use helper fns like
perms::can_read(Perm)
- Make Perm a real type (maybe using bitflags, with a method
to_os_perm()
which returns the right type depending on the OS? The custom type could support tests likeperm.contains(perms::READ)
.
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 agree that this is a tad ugly, but given that we almost exclusively use perms as opaque, and only use the boolean functionality in one place (realloc), I think it's better to keep it simple.
mmap-alloc/src/lib.rs
Outdated
debug_assert!( | ||
layout.size() > 0 && new_layout.size() > 0, | ||
"grow_in_place: size of layout and new_layout must be non-zero" | ||
); |
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 think I'd split this into two asserts, but I don't have a strong opinion either way.
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.
Fixed.
mmap-alloc/src/lib.rs
Outdated
debug_assert!( | ||
layout.size() > 0 && new_layout.size() > 0, | ||
"shrink_in_place: size of layout and new_layout must be non-zero" | ||
); |
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.
Likewise for splitting the assert.
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.
Fixed.
new_size, | ||
perms::get_perm(self.read, true, self.exec), | ||
); | ||
} |
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'd prefer to split this, so if reads are allowed, but not writes, there's no reason to fix permissions on the old allocations, only the new one, to allow writing, then reset them after. Likewise, for the opposite, if writes are allowed, but not reads, we only have to fix permissions on the old allocation, and never have to reset them back.
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.
Again, missing important context in the short preview. Starts here
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.
Fixed.
fb060a2
to
900dae1
Compare
- Add the ability to verify memory permissions by parsing /proc/<pid>/maps on Linux and using the VirtualQuery function on Windows - Remove checks for allocation at the 0 page, as it turns out that these are unnecessary on all platforms that we support (Linux, Mac, Windows) - Change the way boolean configuration functions work for MapAllocBuilder (instead of xxx() and no_xxx(), we now supply a single xxx(xxx: bool) method that accepts a boolean indicating whether the configuration should be on or off) - Fix bugs in realloc tests on Windows - Move tests module into separate file - Remove test-no-std feature Closes #83 Closes #72 and #80 by making them unnecessary since this commit removes the use cases for mark_unused and alloc_helper
900dae1
to
20e6516
Compare
I still think the read/write/exec bools are ugly, but other than that, it all looks good, I'd say this is ready to merge in my eyes. |
/proc/<pid>/maps
on Linux, and incorporate this into existing tests in order to verify permissionsMapAllocBuilder
(instead ofxxx()
andno_xxx()
, we now supply a singlexxx(xxx: bool)
method that accepts a boolean indicating whether the configuration should be on or off)Closes #83.
Closes #72 and #80 by making them unnecessary since this commit removes the use cases for
mark_unused
andalloc_helper
.For posterity: A previous version of the code to verify memory permissions attempted to access a region in order to generate a SIGSEGV signal, and catch that signal. I couldn't get that code working, so I switched to parsing
/proc/<pid>/maps
instead. If somebody wants to take a look and maybe try to get it working, the draft I had before I switched is here.