This is an archive of the discontinued LLVM Phabricator instance.

[Sanitizers] MSan allocator set errno on failure.
ClosedPublic

Authored by alekseyshl on Jul 11 2017, 1:45 PM.

Details

Summary

Set proper errno code on allocation failures and change realloc, pvalloc,
aligned_alloc, memalign and posix_memalign implementation to satisfy
their man-specified requirements.

Modify allocator API implementation to bring it closer to other sanitizers allocators.

Diff Detail

Repository
rL LLVM

Event Timeline

alekseyshl created this revision.Jul 11 2017, 1:45 PM

Instead of the ptr_check calls, couldn't errno be set to ENOMEM in ReturnNullOrDieOnFailure::OnOOM? Unless mistaken it should be the common function to the return nullptr scenario on OOM.
Also you are going to hate me, and I apologize in advance, but when starting Scudo I was asked to follow to LLVM casing scheme, which your additions to Scudo don't comply with :/

alekseyshl edited reviewers, added: kcc; removed: eugenis.Jul 11 2017, 7:11 PM
vitalybuka edited edge metadata.Jul 12 2017, 2:14 PM

Does this need to be a single patch?

Instead of the ptr_check calls, couldn't errno be set to ENOMEM in ReturnNullOrDieOnFailure::OnOOM? Unless mistaken it should be the common function to the return nullptr scenario on OOM.
Also you are going to hate me, and I apologize in advance, but when starting Scudo I was asked to follow to LLVM casing scheme, which your additions to Scudo don't comply with :/

Will change Scudo part to follow your scheme, no problem.

No, unfortunately, I cannot set errno in the policy, posix_memalign does not affect errno and errno is an API concept anyway, I'd like to keep allocator internals oblivious to it.

Does this need to be a single patch?

No, it does not have to be a single patch, would you prefer to see per-sanitizer patches? My idea was that this way it is easier to see the similarities, but I'm fine splitting it into multiple patches.

Does this need to be a single patch?

No, it does not have to be a single patch, would you prefer to see per-sanitizer patches? My idea was that this way it is easier to see the similarities, but I'm fine splitting it into multiple patches.

errno = errno_ENOMEM; and ptr_check changes seems trivial to be in one patch, but replacement MsanReallocate to msan_* probably deserve separate one.

vitalybuka added inline comments.Jul 12 2017, 4:29 PM
lib/asan/asan_allocator.cc
848 ↗(On Diff #106093)

easier to read: size = size ? RoundUpTo(size, PageSize) : PageSize;

lib/scudo/scudo_allocator.cpp
662 ↗(On Diff #106093)

same

vitalybuka added inline comments.Jul 12 2017, 4:47 PM
lib/msan/msan_allocator.cc
269 ↗(On Diff #106093)

why not just (size % alignmet == 0) and ignore "power of two" check?

287 ↗(On Diff #106093)

maybe just, pointer should be always power of two?
if (UNLIKELY((alignment % sizeof(void *)))) {

morehouse added inline comments.Jul 13 2017, 3:19 PM
lib/msan/msan_allocator.cc
287 ↗(On Diff #106093)

From the posix_memalign man page:

The function posix_memalign() allocates size bytes and places the
address of the allocated memory in *memptr. The address of the allo‐
cated memory will be a multiple of alignment, which must be a power of
two and a multiple of sizeof(void *).

morehouse added inline comments.Jul 13 2017, 3:43 PM
lib/msan/msan_allocator.cc
269 ↗(On Diff #106093)

From memalign and aligned_alloc man page:

The obsolete function memalign() allocates size bytes and returns a
pointer to the allocated memory. The memory address will be a multiple
of alignment, which must be a power of two.

The function aligned_alloc() is the same as memalign(), except for the
added restriction that size should be a multiple of alignment.

vitalybuka added inline comments.Jul 13 2017, 4:04 PM
lib/msan/msan_allocator.cc
269 ↗(On Diff #106093)

power of two is posix specific requirement
http://en.cppreference.com/w/c/memory/aligned_alloc

Anyway (size & (alignment - 1)) != 0) can be replaced with simple (size % alignmet)

287 ↗(On Diff #106093)

yes, but sizeof(void *) is already power of two

morehouse edited edge metadata.Jul 13 2017, 4:17 PM

Test cases for EINVAL in the various *memalign and *aligned_alloc functions might be a good idea.

morehouse added inline comments.Jul 14 2017, 7:52 AM
lib/msan/msan_allocator.cc
287 ↗(On Diff #106093)

Suppose sizeof(void *) is 8 and alignment is 24. Then alignment % sizeof(void *) == 0 but alignment is not a power of 2.

vitalybuka added inline comments.Jul 14 2017, 11:22 AM
lib/msan/msan_allocator.cc
287 ↗(On Diff #106093)

i've missed that, thanks for explaining

alekseyshl marked an inline comment as done.Jul 14 2017, 11:40 AM

Test cases for EINVAL in the various *memalign and *aligned_alloc functions might be a good idea.

Yes, I have them on my TODO list, but, with the exception of Scudo, not all platforms implement them and I did not want to revert the entire patch because of those failing tests. Will add them later.

lib/msan/msan_allocator.cc
269 ↗(On Diff #106093)

My man memalign says exactly as quoted earlier, the power of two requirement affects both memalign and aligned_alloc.

Ok, I'll split this patch by the sanitizer and send separate reviews.

Merging with HEAD

alekseyshl retitled this revision from [Sanitizers] ASan/MSan/LSan allocators set errno on failure. to [Sanitizers] MSan allocator set errno on failure..Jul 14 2017, 4:23 PM
alekseyshl edited the summary of this revision. (Show Details)
alekseyshl edited the summary of this revision. (Show Details)
  • Rename the check function and add a few UNLIKELY around.
alekseyshl marked 9 inline comments as done.Jul 14 2017, 6:45 PM
alekseyshl added inline comments.
lib/msan/msan_allocator.cc
269 ↗(On Diff #106093)

(size & (alignment - 1)) != 0) leads to appreciably more compact and faster assembly generated than (size % alignment), because div required for the latter touches a lot of registers, which forces compiler to push other vars around.

The difference is 0x41 vs 0x51 bytes of the function size.

vitalybuka accepted this revision.Jul 14 2017, 7:29 PM
vitalybuka added inline comments.
lib/msan/msan_allocator.cc
231 ↗(On Diff #106745)

maybe move to some common header?

269 ↗(On Diff #106093)

then why msan_posix_memalign uses % when you do the same?

269 ↗(On Diff #106093)

your man is for posix

This revision is now accepted and ready to land.Jul 14 2017, 7:29 PM
alekseyshl marked 3 inline comments as done.Jul 17 2017, 3:29 PM
alekseyshl added inline comments.
lib/msan/msan_allocator.cc
231 ↗(On Diff #106745)

Ok, let's try to common-ise some of the logc here.

269 ↗(On Diff #106093)

Cause it % with compile time constant (which is a power of 2), the compiler was capable to optimize % part of the condition to one bitmask operation there.

269 ↗(On Diff #106093)

Not sure how we can check for "valid alignment supported by the implementation" condition, but I can definitely relax it for non-POSIX platforms.

alekseyshl marked 2 inline comments as done.
  • Move common functions to sanitizer_common.
  • Disable errno test on Windows until we figure out the problem.
This revision was automatically updated to reflect the committed changes.