[compiler-rt] 5f2a74c - [GWP-ASan] Update alignment on Android.
Mitch Phillips via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 12 15:25:48 PST 2020
Author: Mitch Phillips
Date: 2020-02-12T15:24:58-08:00
New Revision: 5f2a74c87abc4ed926e93e75d1c3178723a47322
URL: https://github.com/llvm/llvm-project/commit/5f2a74c87abc4ed926e93e75d1c3178723a47322
DIFF: https://github.com/llvm/llvm-project/commit/5f2a74c87abc4ed926e93e75d1c3178723a47322.diff
LOG: [GWP-ASan] Update alignment on Android.
Summary:
Android has different alignment requirements. You can read more about
them here
(https://cs.android.com/android/platform/superproject/+/master:bionic/tests/malloc_test.cpp;l=808),
but the general gist is that for malloc(x <= 8), we do malloc(8), and
for everything else, we do 16-byte alignment.
Reviewers: eugenis, morehouse, cferris
Reviewed By: eugenis, morehouse
Subscribers: #sanitizers, llvm-commits, pcc
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D74364
Added:
Modified:
compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp
compiler-rt/lib/gwp_asan/guarded_pool_allocator.h
compiler-rt/lib/gwp_asan/options.inc
compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp
compiler-rt/lib/gwp_asan/tests/alignment.cpp
compiler-rt/lib/gwp_asan/utilities.h
Removed:
################################################################################
diff --git a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp
index 7af99e482f3d..b2602e4caa59 100644
--- a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp
+++ b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp
@@ -8,9 +8,10 @@
#include "gwp_asan/guarded_pool_allocator.h"
+#include "gwp_asan/optional/segv_handler.h"
#include "gwp_asan/options.h"
+#include "gwp_asan/random.h"
#include "gwp_asan/utilities.h"
-#include "optional/segv_handler.h"
// RHEL creates the PRIu64 format macro (for printing uint64_t's) only when this
// macro is defined before including <inttypes.h>.
@@ -175,7 +176,14 @@ void *GuardedPoolAllocator::allocate(size_t Size) {
return nullptr;
uintptr_t Ptr = State.slotToAddr(Index);
- Ptr += allocationSlotOffset(Size);
+ // Should we right-align this allocation?
+ if (getRandomUnsigned32() % 2 == 0) {
+ AlignmentStrategy Align = AlignmentStrategy::DEFAULT;
+ if (PerfectlyRightAlign)
+ Align = AlignmentStrategy::PERFECT;
+ Ptr +=
+ State.maximumAllocationSize() - rightAlignedAllocationSize(Size, Align);
+ }
AllocationMetadata *Meta = addrToMetadata(Ptr);
// If a slot is multiple pages in size, and the allocation takes up a single
@@ -278,26 +286,6 @@ void GuardedPoolAllocator::freeSlot(size_t SlotIndex) {
FreeSlots[FreeSlotsLength++] = SlotIndex;
}
-uintptr_t GuardedPoolAllocator::allocationSlotOffset(size_t Size) const {
- assert(Size > 0);
-
- bool ShouldRightAlign = getRandomUnsigned32() % 2 == 0;
- if (!ShouldRightAlign)
- return 0;
-
- uintptr_t Offset = State.maximumAllocationSize();
- if (!PerfectlyRightAlign) {
- if (Size == 3)
- Size = 4;
- else if (Size > 4 && Size <= 8)
- Size = 8;
- else if (Size > 8 && (Size % 16) != 0)
- Size += 16 - (Size % 16);
- }
- Offset -= Size;
- return Offset;
-}
-
GWP_ASAN_TLS_INITIAL_EXEC
GuardedPoolAllocator::ThreadLocalPackedVariables
GuardedPoolAllocator::ThreadLocals;
diff --git a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h
index 53d1635346f0..ae00506c5692 100644
--- a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h
+++ b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h
@@ -149,11 +149,6 @@ class GuardedPoolAllocator {
// Unreserve the guarded slot.
void freeSlot(size_t SlotIndex);
- // Returns the offset (in bytes) between the start of a guarded slot and where
- // the start of the allocation should take place. Determined using the size of
- // the allocation and the options provided at init-time.
- uintptr_t allocationSlotOffset(size_t AllocationSize) const;
-
// Raise a SEGV and set the corresponding fields in the Allocator's State in
// order to tell the crash handler what happened. Used when errors are
// detected internally (Double Free, Invalid Free).
diff --git a/compiler-rt/lib/gwp_asan/options.inc b/compiler-rt/lib/gwp_asan/options.inc
index 3b941b19af5e..6cdddfbad84d 100644
--- a/compiler-rt/lib/gwp_asan/options.inc
+++ b/compiler-rt/lib/gwp_asan/options.inc
@@ -17,9 +17,10 @@ GWP_ASAN_OPTION(
"When allocations are right-aligned, should we perfectly align them up to "
"the page boundary? By default (false), we round up allocation size to the "
"nearest power of two (1, 2, 4, 8, 16) up to a maximum of 16-byte "
- "alignment for performance reasons. Setting this to true can find single "
- "byte buffer-overflows for multibyte allocations at the cost of "
- "performance, and may be incompatible with some architectures.")
+ "alignment for performance reasons. For Bionic, we use 8-byte alignment by "
+ "default. Setting this to true can find single byte buffer-overflows for "
+ "multibyte allocations at the cost of performance, and may be incompatible "
+ "with some architectures.")
GWP_ASAN_OPTION(int, MaxSimultaneousAllocations, 16,
"Number of simultaneously-guarded allocations available in the "
diff --git a/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp b/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp
index 68d7ee7867a9..2e7403458af5 100644
--- a/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp
+++ b/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp
@@ -9,16 +9,18 @@
#include "gwp_asan/definitions.h"
#include "gwp_asan/utilities.h"
-#ifdef ANDROID
+#include <assert.h>
+
+#ifdef __BIONIC__
#include <stdlib.h>
extern "C" GWP_ASAN_WEAK void android_set_abort_message(const char *);
-#else // ANDROID
+#else // __BIONIC__
#include <stdio.h>
#endif
namespace gwp_asan {
-#ifdef ANDROID
+#ifdef __BIONIC__
void Check(bool Condition, const char *Message) {
if (Condition)
return;
@@ -26,13 +28,62 @@ void Check(bool Condition, const char *Message) {
android_set_abort_message(Message);
abort();
}
-#else // ANDROID
+#else // __BIONIC__
void Check(bool Condition, const char *Message) {
if (Condition)
return;
fprintf(stderr, "%s", Message);
__builtin_trap();
}
-#endif // ANDROID
+#endif // __BIONIC__
+
+// See `bionic/tests/malloc_test.cpp` in the Android source for documentation
+// regarding their alignment guarantees. We always round up to the closest
+// 8-byte window. As GWP-ASan's malloc(X) can always get exactly an X-sized
+// allocation, an allocation that rounds up to 16-bytes will always be given a
+// 16-byte aligned allocation.
+static size_t alignBionic(size_t RealAllocationSize) {
+ if (RealAllocationSize % 8 == 0)
+ return RealAllocationSize;
+ return RealAllocationSize + 8 - (RealAllocationSize % 8);
+}
+
+static size_t alignPowerOfTwo(size_t RealAllocationSize) {
+ if (RealAllocationSize <= 2)
+ return RealAllocationSize;
+ if (RealAllocationSize <= 4)
+ return 4;
+ if (RealAllocationSize <= 8)
+ return 8;
+ if (RealAllocationSize % 16 == 0)
+ return RealAllocationSize;
+ return RealAllocationSize + 16 - (RealAllocationSize % 16);
+}
+
+#ifdef __BIONIC__
+static constexpr AlignmentStrategy PlatformDefaultAlignment =
+ AlignmentStrategy::ANDROID;
+#else // __BIONIC__
+static constexpr AlignmentStrategy PlatformDefaultAlignment =
+ AlignmentStrategy::POWER_OF_TWO;
+#endif // __BIONIC__
+
+size_t rightAlignedAllocationSize(size_t RealAllocationSize,
+ AlignmentStrategy Align) {
+ assert(RealAllocationSize > 0);
+ if (Align == AlignmentStrategy::DEFAULT)
+ Align = PlatformDefaultAlignment;
+
+ switch (Align) {
+ case AlignmentStrategy::BIONIC:
+ return alignBionic(RealAllocationSize);
+ case AlignmentStrategy::POWER_OF_TWO:
+ return alignPowerOfTwo(RealAllocationSize);
+ case AlignmentStrategy::PERFECT:
+ return RealAllocationSize;
+ case AlignmentStrategy::DEFAULT:
+ __builtin_unreachable();
+ }
+}
} // namespace gwp_asan
diff --git a/compiler-rt/lib/gwp_asan/tests/alignment.cpp b/compiler-rt/lib/gwp_asan/tests/alignment.cpp
index 8b1ce8ccd712..bf98f1f58338 100644
--- a/compiler-rt/lib/gwp_asan/tests/alignment.cpp
+++ b/compiler-rt/lib/gwp_asan/tests/alignment.cpp
@@ -7,21 +7,38 @@
//===----------------------------------------------------------------------===//
#include "gwp_asan/tests/harness.h"
+#include "gwp_asan/utilities.h"
-TEST_F(DefaultGuardedPoolAllocator, BasicAllocation) {
- std::vector<std::pair<int, int>> AllocSizeToAlignment = {
+TEST(AlignmentTest, PowerOfTwo) {
+ std::vector<std::pair<size_t, size_t>> AskedSizeToAlignedSize = {
{1, 1}, {2, 2}, {3, 4}, {4, 4}, {5, 8}, {7, 8},
- {8, 8}, {9, 16}, {15, 16}, {16, 16}, {17, 16}, {31, 16},
- {32, 16}, {33, 16}, {4095, 4096}, {4096, 4096},
+ {8, 8}, {9, 16}, {15, 16}, {16, 16}, {17, 32}, {31, 32},
+ {32, 32}, {33, 48}, {4095, 4096}, {4096, 4096},
};
- for (const auto &KV : AllocSizeToAlignment) {
- void *Ptr = GPA.allocate(KV.first);
- EXPECT_NE(nullptr, Ptr);
+ for (const auto &KV : AskedSizeToAlignedSize) {
+ EXPECT_EQ(KV.second,
+ gwp_asan::rightAlignedAllocationSize(
+ KV.first, gwp_asan::AlignmentStrategy::POWER_OF_TWO));
+ }
+}
+
+TEST(AlignmentTest, AlignBionic) {
+ std::vector<std::pair<size_t, size_t>> AskedSizeToAlignedSize = {
+ {1, 8}, {2, 8}, {3, 8}, {4, 8}, {5, 8}, {7, 8},
+ {8, 8}, {9, 16}, {15, 16}, {16, 16}, {17, 24}, {31, 32},
+ {32, 32}, {33, 40}, {4095, 4096}, {4096, 4096},
+ };
- // Check the alignment of the pointer is as expected.
- EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(Ptr) % KV.second);
+ for (const auto &KV : AskedSizeToAlignedSize) {
+ EXPECT_EQ(KV.second, gwp_asan::rightAlignedAllocationSize(
+ KV.first, gwp_asan::AlignmentStrategy::BIONIC));
+ }
+}
- GPA.deallocate(Ptr);
+TEST(AlignmentTest, PerfectAlignment) {
+ for (size_t i = 1; i <= 4096; ++i) {
+ EXPECT_EQ(i, gwp_asan::rightAlignedAllocationSize(
+ i, gwp_asan::AlignmentStrategy::PERFECT));
}
}
diff --git a/compiler-rt/lib/gwp_asan/utilities.h b/compiler-rt/lib/gwp_asan/utilities.h
index c307b381fe5f..71d525f9e14c 100644
--- a/compiler-rt/lib/gwp_asan/utilities.h
+++ b/compiler-rt/lib/gwp_asan/utilities.h
@@ -8,8 +8,24 @@
#include "gwp_asan/definitions.h"
+#include <stddef.h>
+#include <stdint.h>
+
namespace gwp_asan {
// Checks that `Condition` is true, otherwise fails in a platform-specific way
// with `Message`.
void Check(bool Condition, const char *Message);
+
+enum class AlignmentStrategy {
+ // Default => POWER_OF_TWO on most platforms, BIONIC for Android Bionic.
+ DEFAULT,
+ POWER_OF_TWO,
+ BIONIC,
+ PERFECT,
+};
+
+// Returns the real size of a right-aligned allocation.
+size_t rightAlignedAllocationSize(
+ size_t RealAllocationSize,
+ AlignmentStrategy Align = AlignmentStrategy::DEFAULT);
} // namespace gwp_asan
More information about the llvm-commits
mailing list