This is an archive of the discontinued LLVM Phabricator instance.

Introduce ReservedAddressRange to sanitizer_common.
ClosedPublic

Authored by flowerhack on Sep 29 2017, 5:23 PM.

Details

Summary

In Fuchsia, MmapNoAccess/MmapFixedOrDie are implemented using a global
VMAR, which means that MmapNoAccess can only be called once. This works
for the sanitizer allocator but *not* for the Scudo allocator.

Hence, this changeset introduces a new ReservedAddressRange object to
serve as the new API for these calls. In this changeset, the object
still calls into the old Mmap implementations.

The next changeset two changesets will convert the sanitizer and scudo
allocators to use the new APIs, respectively. (ReservedAddressRange will
replace the SecondaryHeader in Scudo.)

Finally, a last changeset will update the Fuchsia implementation.

Feedback welcome, can provide code pointers to the upcoming changesets
upon request, etc

Diff Detail

Event Timeline

flowerhack created this revision.Sep 29 2017, 5:23 PM
alekseyshl edited edge metadata.Oct 3 2017, 11:33 AM

Code pointers to the future changes would be nice, actually.

compiler-rt/lib/sanitizer_common/sanitizer_common.h
86 ↗(On Diff #117248)

In what way?

95 ↗(On Diff #117248)

No one but Fuchsia will need it, I guess?

compiler-rt/lib/sanitizer_common/sanitizer_posix.cc
152 ↗(On Diff #117248)

What's the point having it here? If sanitizer_posix_libcdep.cc is not included in the build, ReservedAddressRange::Init is not defined anyway.

cryptoad edited edge metadata.Oct 3 2017, 11:37 AM

For this first one, I think having the unmapping being implemented as well would be advised.

compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h
213 ↗(On Diff #117248)

What will be the point of those two functions?

compiler-rt/lib/sanitizer_common/sanitizer_common.h
89 ↗(On Diff #117248)

It could be better to have the parameters order mimic the MmapFixedNoAccess one: eg, address first.

90 ↗(On Diff #117248)

enomem is too specific here, it might not translate to Windows platforms etc.
You might want something more like die_on_fatal_error or something shorter.

95 ↗(On Diff #117248)

I think the name os_cookie is clear enough.
platform_specific_data or something to that extent maybe?

96 ↗(On Diff #117248)

Missing a #pragma clang diagnostic pop
I'll let someone chime in about what is the pragma policy in sanitizer_common if any.

compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
486 ↗(On Diff #117248)

Split the tests please.
ReservedAddressRange should work for both 32 & 64 bit and should be independent of the allocator (and particularly from the Primary).
The tested workflows should be in general area of init, valid map check, init invalid map, check and stuff like that.

flowerhack updated this revision to Diff 117904.Oct 5 2017, 2:51 PM
flowerhack marked 6 inline comments as done.

responded to feedback, added more tests

compiler-rt/lib/sanitizer_common/sanitizer_common.h
86 ↗(On Diff #117248)

oh, hm, it doesn't yet. the Fuchsia implementation uses it to check whether it's already been initialized, but i'll pull that out of here since it's confusing in this context

89 ↗(On Diff #117248)

thanks for catching that; i had that elsewhere but forgot to fix it here!

90 ↗(On Diff #117248)

On every platform this is implemented for (Windows, Fuchsia, POSIX), MmapFixedOrDieOnFatalError is actually just checking for the "out of memory" condition. Also, the function declaration in sanitizer_common.h specifically says "Behaves just like MmapFixedOrDie, but tolerates out of memory condition"--so I thought it made sense to just use a variable to indicate what it's *actually* checking for. Are there cases where you imagine this won't be true in the future that I'm not thinking of?

95 ↗(On Diff #117248)

that's correct, at least for now (not sure who else would need it)

96 ↗(On Diff #117248)

done.

to whoever plans to chime in on pragma policy: this pragma will be removed once all the patches are in. i can make a TODO, or remove it for now, whichever works better

compiler-rt/lib/sanitizer_common/sanitizer_posix.cc
152 ↗(On Diff #117248)

good point. was trying to match MmapFixedOrDie closely as possible, but, it seems like that function never actually is included in anything that *doesn't* have access to libcdep. moved to libcdep

Oh, and re: the comment about code pointers being helpful: here's what the next three patches should look like:

mcgrathr added inline comments.Oct 5 2017, 3:26 PM
compiler-rt/lib/sanitizer_common/sanitizer_common.h
91 ↗(On Diff #117904)

It should have a const char *name_ member and Init should set it.

94 ↗(On Diff #117904)

Rather than the #pragma stuff, you could just leave this out and only add it along with the Fuchsia implementation.

flowerhack updated this revision to Diff 117934.Oct 5 2017, 4:34 PM
flowerhack marked 3 inline comments as done.

responded to comments so far...

flowerhack added inline comments.Oct 5 2017, 4:35 PM
compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h
213 ↗(On Diff #117248)

removed

cryptoad added inline comments.Oct 6 2017, 8:37 AM
compiler-rt/lib/sanitizer_common/sanitizer_common.h
88 ↗(On Diff #117934)

Thanks for changing the Map parameters order, Init should be changed too for consistency.

compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc
282 ↗(On Diff #117934)

Unmap is going to be tricky.
What if we unmap the middle? Then we end up with 2 mapped areas and the Reserved address range doesn't represent it properly.
For now you might want to enforce strong constraints: eg: either unmap the beginning, or the end, but not the middle.
eg addr==base_ or addr+size==base_+size_ or both (careful with overflows there).
That goes for all Unmap not just Fuchsia's.

compiler-rt/lib/sanitizer_common/sanitizer_win.cc
276 ↗(On Diff #117934)

Windows unmap has even more requirements.
I don't think you can do partial unmapping (eg: VirtualFree requires the entire range of pages passed to Virtual alloc to be released).
So there should be more constraints.

compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cc
340 ↗(On Diff #117934)

Please add some unmapping tests as well.

flowerhack updated this revision to Diff 118091.Oct 6 2017, 3:04 PM
flowerhack marked 2 inline comments as done.

responding to feedback

compiler-rt/lib/sanitizer_common/sanitizer_common.h
88 ↗(On Diff #117934)

Init is almost always called without an address, though, just the size. Does it make sense to have the caller pass in a null address the majority of the time, rather than just having it be an optional later argument?

compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc
282 ↗(On Diff #117934)

wfm, fixed

compiler-rt/lib/sanitizer_common/sanitizer_win.cc
276 ↗(On Diff #117934)

I see those constraints are enforced by a CHECK failure in the UnmapOrDie function that's being called. Are you saying those should be moved into this wrapper function?

cryptoad added inline comments.Oct 9 2017, 10:26 AM
compiler-rt/lib/sanitizer_common/sanitizer_common.h
139 ↗(On Diff #118091)

One nit here: CHECK includes UNLIKELY, so doing it that way, (eg: test outside of CHECK), you don't get the benefit of the UNLIKELY.
Ideally the tests would be wrapped within the CHECK (with a && "string" if neede).

cryptoad added inline comments.Oct 9 2017, 10:29 AM
compiler-rt/lib/sanitizer_common/sanitizer_common.h
88 ↗(On Diff #117934)

Ack. Nevermind then!

compiler-rt/lib/sanitizer_common/sanitizer_win.cc
276 ↗(On Diff #117934)

You are right, let's leave it that way!

alekseyshl accepted this revision.Oct 9 2017, 2:32 PM

Other than those couple comments, lgtm.

compiler-rt/lib/sanitizer_common/sanitizer_common.h
133 ↗(On Diff #118091)

How about calling it Reserve()?

151 ↗(On Diff #118091)

Can you move the implementation to .cc? It's not a template and it's not trivial.

This revision is now accepted and ready to land.Oct 9 2017, 2:32 PM
mcgrathr added inline comments.Oct 9 2017, 2:46 PM
compiler-rt/lib/sanitizer_common/sanitizer_common.h
133 ↗(On Diff #118091)

The object represents the reservation and Init is canonical for "constructor that can return an error".
"Initialize the reservation object" makes sense.
"Reserve in the reservation object" makes less sense.

flowerhack marked 4 inline comments as done.

responding to comments

compiler-rt/lib/sanitizer_common/sanitizer_common.h
139 ↗(On Diff #118091)

oh cool, TIL! updated

marking some stuff as done

apparently the file root / base was off; this is an attempt to rebate it so the patch applies cleanly

alekseyshl accepted this revision.Oct 11 2017, 10:21 AM
alekseyshl added inline comments.
lib/sanitizer_common/sanitizer_common.h
137

Make base() and size() const.

flowerhack marked an inline comment as done.

fixing last feedback

lib/sanitizer_common/sanitizer_common.h
137

fixed

fix windows breakage

fix android tests

fix android build

This revision was automatically updated to reflect the committed changes.