This is an archive of the discontinued LLVM Phabricator instance.

[sanitizer] Change Mmap*NoAccess to return nullptr on error
ClosedPublic

Authored by cryptoad on Aug 18 2018, 5:00 PM.

Details

Summary

MmapNoAccess & MmapFixedNoAccess return directly the result of
internal_mmap, as opposed to other Mmap functions that return nullptr.

This inconsistency leads to some confusion for the callers, as some check for
~(uptr)0 (MAP_FAILED) for failure (while it can fail with -ENOMEM for
example).

Two potential solutions: change the callers, or make the functions return
nullptr on failure to follow the precedent set by the other functions.
The second option looked more appropriate to me.

Correct the callers that were wrongly checking for ~(uptr)0 or
MAP_FAILED.

TODO for follow up CLs:

  • There are a couple of internal_mmap calls in XRay that check for MMAP_FAILED as a result as well (cc: @dberris); they should use internal_iserror;

Diff Detail

Event Timeline

cryptoad created this revision.Aug 18 2018, 5:00 PM
Herald added subscribers: Restricted Project, delcypher, kubamracek. · View Herald TranscriptAug 18 2018, 5:00 PM

I would expect it to just forward the return code from the original call since sanitizes already abstract away a lot of things, having more even more abstractions internally seems over the top as they're not public interfaces. I think it's best to fix the incorrect uses and perhaps document it in a more obvious way.

I guess after scavenging further, my initial patch is not correct, as other functions return nullptr on failure.
I am open to anything if we can get a consensus on what should be returned.

Here is the current state:

MmapOrDie: pointer or death
MmapOrDieOnFatalError: pointer, nullptr, or death
MmapAlignedOrDieOnFatalError: pointer, nullptr, or death
MmapNoReserveOrDie: pointer or death
MmapFixedImpl: pointer, nullptr, or death
MmapNoAccess: syscall return value (eg: pointer or -error) [on Windows it returns the result of VirtualAlloc which is NULL on failure)
MmapFixedNoAccess: syscall return value (eg: pointer or -error) [same as above for Windows]

The current wrong usage:
sanitizer::SizeClassAllocator64::Init: checks for failure with ~(uptr)0 (while it's the syscall return value)
sanitizer::LargeMmapAllocatorPtrDynamicArray::Init: checks for failure with nullptr (while it's the syscall return value)
scudo::LargeMmapAllocator::Allocate: checks for failure with ~(uptr)0 (while it's the syscall return value)
xray::profileCollectorService::allocateBuffer: checks for failure with MMAP_FAILED (while it's the syscall return value)
same with __xray::Allocator::Alloc & alocRaw

Other wrong use:
hwasan::MapDynamicShadow: checks for failure with ~(uptr)0 (while it's the syscall return value)
asan::FindDynamicShadowStart: same as above
__asan::PremapShadow: same as above

I do support the unification of the return value, and if no call site is currently care for the actual syscall return value, I'd say, let's make all of them return pointer, nullptr or die. MMAP_FAILED might be a reasonable common ground too, but seems like nullptr is used in many places already and Windows returns NULL on failure, so a bit more unification across platforms here.

cryptoad updated this revision to Diff 161523.Aug 20 2018, 11:37 AM

Updated proposal: make Mmap*NoAccess return nullptr on failure (like the
other Mmap functions).
Modify callers that were checking for ~(uptr)0 to now check for nullptr.

cryptoad retitled this revision from [sanitizer] Change Mmap*NoAccess to return MMAP_FAILED (~(uptr)0) on error to [sanitizer] Change Mmap*NoAccess to return nullptr on error.Aug 20 2018, 11:40 AM
cryptoad edited the summary of this revision. (Show Details)
cryptoad added a reviewer: kubamracek.

I do support the unification of the return value, and if no call site is currently care for the actual syscall return value, I'd say, let's make all of them return pointer, nullptr or die. MMAP_FAILED might be a reasonable common ground too, but seems like nullptr is used in many places already and Windows returns NULL on failure, so a bit more unification across platforms here.

I think that's a reasonable common ground, seems much better than sanitizers being plagued with the TLV errno idiom, so something like a CHECK on a failed mmap call or just returning NULL (I think latter is better since this concerns the common code used by all sanitizes and some may want to recover).

alekseyshl accepted this revision.Aug 23 2018, 12:49 PM
This revision is now accepted and ready to land.Aug 23 2018, 12:49 PM
This revision was automatically updated to reflect the committed changes.

Link to test source: https://github.com/llvm-mirror/compiler-rt/blob/master/test/msan/mmap.cc#L78
Last test output: 0xf00000000
Link to msan mmap interceptor: https://github.com/llvm-mirror/compiler-rt/blob/master/lib/msan/msan_interceptors.cc#L939

As far as I understand, this test is failing because 0xf00000000 is not within the allowed AddrMapping for aarch64.
I am not sure how those mappings where added to the list in the first place.
Looking at mmap_interceptor for msan, I don't think the patch impacts it at all (it just calls real_mmap)

I'll setting up an aarch64 environment, I'll try and add the new mapping(s) and see how it fairs (unless someone can beat me to it - I only have a BBB for AArch64 so it's going to take a while)