diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-02-17 03:31:51 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-02-17 03:31:51 +0000 |
commit | 873935e24f28a742258dce0c488942416acae152 (patch) | |
tree | 1310d30a760d2309aeea9845a45dfe3f3f3633f9 | |
parent | 154587cb48e6d6c569b69859e496a4467a65c576 (diff) | |
parent | 540563280a95233750aeaf2caa0f07450e1c24fd (diff) | |
download | gwp_asan-873935e24f28a742258dce0c488942416acae152.tar.gz |
Snap for 8191477 from 540563280a95233750aeaf2caa0f07450e1c24fd to tm-frc-resolv-release
Change-Id: I6d6572c95c7da996cb8c4db9311dd84006cafc76
-rw-r--r-- | Android.bp | 9 | ||||
-rw-r--r-- | gwp_asan/common.h | 57 | ||||
-rw-r--r-- | gwp_asan/guarded_pool_allocator.cpp | 12 | ||||
-rwxr-xr-x | gwp_asan/scripts/symbolize.sh | 8 | ||||
-rw-r--r-- | gwp_asan/tests/alignment.cpp | 42 | ||||
-rw-r--r-- | gwp_asan/tests/backtrace.cpp | 9 | ||||
-rw-r--r-- | gwp_asan/tests/enable_disable.cpp | 2 | ||||
-rw-r--r-- | gwp_asan/tests/harness.h | 5 |
8 files changed, 111 insertions, 33 deletions
@@ -71,7 +71,12 @@ cc_defaults { // GWP-ASan is used by bionic libc, and should have no libc/libc++ // dependencies. - system_shared_libs: [], + target: { + bionic: { + system_shared_libs: [], + header_libs: ["libc_headers"], + }, + }, stl: "none", } @@ -104,7 +109,6 @@ cc_library_static { defaults: ["gwp_asan_no_libs_defaults"], header_libs: [ "gwp_asan_headers", - "libc_headers", // Required for pthread.h in mutex.h. ], srcs: [ "gwp_asan/common.cpp", @@ -139,7 +143,6 @@ cc_library { defaults: ["gwp_asan_defaults"], header_libs: [ "gwp_asan_headers", - "libc_headers", // Required for assert.h ], srcs: [ "gwp_asan/common.cpp", diff --git a/gwp_asan/common.h b/gwp_asan/common.h index 7ce367e..6b238ad 100644 --- a/gwp_asan/common.h +++ b/gwp_asan/common.h @@ -19,7 +19,28 @@ #include <stdint.h> namespace gwp_asan { -enum class Error { + +// Magic header that resides in the AllocatorState so that GWP-ASan bugreports +// can be understood by tools at different versions. Out-of-process crash +// handlers, like crashpad on Fuchsia, take the raw contents of the +// AllocationMetatada array and the AllocatorState, and shove them into the +// minidump. Online unpacking of these structs needs to know from which version +// of GWP-ASan it's extracting the information, as the structures are not +// stable. +struct AllocatorVersionMagic { + // The values are copied into the structure at runtime, during + // `GuardedPoolAllocator::init()` so that GWP-ASan remains completely in the + // `.bss` segment. + static constexpr uint8_t kAllocatorVersionMagic[4] = {'A', 'S', 'A', 'N'}; + uint8_t Magic[4] = {}; + // Update the version number when the AllocatorState or AllocationMetadata + // change. + static constexpr uint16_t kAllocatorVersion = 1; + uint16_t Version = 0; + uint16_t Reserved = 0; +}; + +enum class Error : uint8_t { UNKNOWN, USE_AFTER_FREE, DOUBLE_FREE, @@ -84,6 +105,7 @@ struct AllocationMetadata { // set of information required for understanding a GWP-ASan crash. struct AllocatorState { constexpr AllocatorState() {} + AllocatorVersionMagic VersionMagic{}; // Returns whether the provided pointer is a current sampled allocation that // is owned by this pool. @@ -123,5 +145,38 @@ struct AllocatorState { uintptr_t FailureAddress = 0; }; +// Below are various compile-time checks that the layout of the internal +// GWP-ASan structures are undisturbed. If they are disturbed, the version magic +// number needs to be increased by one, and the asserts need to be updated. +// Out-of-process crash handlers, like breakpad/crashpad, may copy the internal +// GWP-ASan structures into a minidump for offline reconstruction of the crash. +// In order to accomplish this, the offline reconstructor needs to know the +// version of GWP-ASan internal structures that it's unpacking (along with the +// architecture-specific layout info, which is left as an exercise to the crash +// handler). +static_assert(offsetof(AllocatorState, VersionMagic) == 0, ""); +static_assert(sizeof(AllocatorVersionMagic) == 8, ""); +#if defined(__x86_64__) +static_assert(sizeof(AllocatorState) == 56, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 48, ""); +static_assert(sizeof(AllocationMetadata) == 568, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 560, ""); +#elif defined(__aarch64__) +static_assert(sizeof(AllocatorState) == 56, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 48, ""); +static_assert(sizeof(AllocationMetadata) == 568, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 560, ""); +#elif defined(__i386__) +static_assert(sizeof(AllocatorState) == 32, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 28, ""); +static_assert(sizeof(AllocationMetadata) == 548, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 544, ""); +#elif defined(__arm__) +static_assert(sizeof(AllocatorState) == 32, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 28, ""); +static_assert(sizeof(AllocationMetadata) == 560, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 552, ""); +#endif // defined($ARCHITECTURE) + } // namespace gwp_asan #endif // GWP_ASAN_COMMON_H_ diff --git a/gwp_asan/guarded_pool_allocator.cpp b/gwp_asan/guarded_pool_allocator.cpp index d784927..7096b42 100644 --- a/gwp_asan/guarded_pool_allocator.cpp +++ b/gwp_asan/guarded_pool_allocator.cpp @@ -59,6 +59,13 @@ void GuardedPoolAllocator::init(const options::Options &Opts) { SingletonPtr = this; Backtrace = Opts.Backtrace; + State.VersionMagic = {{AllocatorVersionMagic::kAllocatorVersionMagic[0], + AllocatorVersionMagic::kAllocatorVersionMagic[1], + AllocatorVersionMagic::kAllocatorVersionMagic[2], + AllocatorVersionMagic::kAllocatorVersionMagic[3]}, + AllocatorVersionMagic::kAllocatorVersion, + 0}; + State.MaxSimultaneousAllocations = Opts.MaxSimultaneousAllocations; const size_t PageSize = getPlatformPageSize(); @@ -258,7 +265,10 @@ void GuardedPoolAllocator::trapOnAddress(uintptr_t Address, Error E) { // Raise a SEGV by touching first guard page. volatile char *p = reinterpret_cast<char *>(State.GuardedPagePool); *p = 0; - __builtin_unreachable(); + // Normally, would be __builtin_unreachable(), but because of + // https://bugs.llvm.org/show_bug.cgi?id=47480, unreachable will DCE the + // volatile store above, even though it has side effects. + __builtin_trap(); } void GuardedPoolAllocator::stop() { diff --git a/gwp_asan/scripts/symbolize.sh b/gwp_asan/scripts/symbolize.sh index fad9620..0027fa0 100755 --- a/gwp_asan/scripts/symbolize.sh +++ b/gwp_asan/scripts/symbolize.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # The lines that we're looking to symbolize look like this: #0 ./a.out(_foo+0x3e6) [0x55a52e64c696] @@ -25,7 +25,7 @@ while read -r line; do if [ -z "$function_name" ]; then # If the offset is binary-relative, just resolve that. - symbolized="$(echo $function_offset | addr2line -e $binary_name)" + symbolized="$(echo $function_offset | addr2line -ie $binary_name)" else # Otherwise, the offset is function-relative. Get the address of the # function, and add it to the offset, then symbolize. @@ -41,7 +41,7 @@ while read -r line; do # Add the function address and offset to get the offset into the binary. binary_offset="$(printf "0x%X" "$((function_addr+function_offset))")" - symbolized="$(echo $binary_offset | addr2line -e $binary_name)" + symbolized="$(echo $binary_offset | addr2line -ie $binary_name)" fi # Check that it symbolized properly. If it didn't, output the old line. @@ -52,4 +52,4 @@ while read -r line; do else echo "${frame_number}${symbolized}" fi -done +done 2> >(grep -v "addr2line: DWARF error: could not find variable specification") diff --git a/gwp_asan/tests/alignment.cpp b/gwp_asan/tests/alignment.cpp index 5f24a9a..6d1e912 100644 --- a/gwp_asan/tests/alignment.cpp +++ b/gwp_asan/tests/alignment.cpp @@ -34,81 +34,81 @@ public: // numerics of the testing. TEST(AlignmentTest, LeftAlignedAllocs) { // Alignment < Page Size. - EXPECT_EQ(0x4000, AlignmentTestGPA::alignUp( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignUp( /* Ptr */ 0x4000, /* Alignment */ 0x1)); // Alignment == Page Size. - EXPECT_EQ(0x4000, AlignmentTestGPA::alignUp( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignUp( /* Ptr */ 0x4000, /* Alignment */ 0x1000)); // Alignment > Page Size. - EXPECT_EQ(0x4000, AlignmentTestGPA::alignUp( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignUp( /* Ptr */ 0x4000, /* Alignment */ 0x4000)); } TEST(AlignmentTest, SingleByteAllocs) { // Alignment < Page Size. - EXPECT_EQ(0x1, + EXPECT_EQ(0x1u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1, /* Alignment */ 0x1, /* PageSize */ 0x1000)); - EXPECT_EQ(0x7fff, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x7fffu, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1, /* Alignment */ 0x1)); // Alignment == Page Size. - EXPECT_EQ(0x1, + EXPECT_EQ(0x1u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1, /* Alignment */ 0x1000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x7000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x7000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1, /* Alignment */ 0x1000)); // Alignment > Page Size. - EXPECT_EQ(0x3001, + EXPECT_EQ(0x3001u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1, /* Alignment */ 0x4000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x4000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1, /* Alignment */ 0x4000)); } TEST(AlignmentTest, PageSizedAllocs) { // Alignment < Page Size. - EXPECT_EQ(0x1000, + EXPECT_EQ(0x1000u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1000, /* Alignment */ 0x1, /* PageSize */ 0x1000)); - EXPECT_EQ(0x7000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x7000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1000, /* Alignment */ 0x1)); // Alignment == Page Size. - EXPECT_EQ(0x1000, AlignmentTestGPA::getRequiredBackingSize( + EXPECT_EQ(0x1000u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1000, /* Alignment */ 0x1000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x7000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x7000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1000, /* Alignment */ 0x1000)); // Alignment > Page Size. - EXPECT_EQ(0x4000, AlignmentTestGPA::getRequiredBackingSize( + EXPECT_EQ(0x4000u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1000, /* Alignment */ 0x4000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x4000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1000, /* Alignment */ 0x4000)); } TEST(AlignmentTest, MoreThanPageAllocs) { // Alignment < Page Size. - EXPECT_EQ(0x2fff, + EXPECT_EQ(0x2fffu, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x2fff, /* Alignment */ 0x1, /* PageSize */ 0x1000)); - EXPECT_EQ(0x5001, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x5001u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x2fff, /* Alignment */ 0x1)); // Alignment == Page Size. - EXPECT_EQ(0x2fff, AlignmentTestGPA::getRequiredBackingSize( + EXPECT_EQ(0x2fffu, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x2fff, /* Alignment */ 0x1000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x5000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x5000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x2fff, /* Alignment */ 0x1000)); // Alignment > Page Size. - EXPECT_EQ(0x5fff, AlignmentTestGPA::getRequiredBackingSize( + EXPECT_EQ(0x5fffu, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x2fff, /* Alignment */ 0x4000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x4000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x2fff, /* Alignment */ 0x4000)); } diff --git a/gwp_asan/tests/backtrace.cpp b/gwp_asan/tests/backtrace.cpp index 9515065..a4eb8eb 100644 --- a/gwp_asan/tests/backtrace.cpp +++ b/gwp_asan/tests/backtrace.cpp @@ -30,7 +30,7 @@ __attribute__((optnone)) void TouchMemory(void *Ptr) { *(reinterpret_cast<volatile char *>(Ptr)) = 7; } -TEST_F(BacktraceGuardedPoolAllocator, DoubleFree) { +TEST_F(BacktraceGuardedPoolAllocatorDeathTest, DoubleFree) { void *Ptr = AllocateMemory(GPA); DeallocateMemory(GPA, Ptr); @@ -45,7 +45,12 @@ TEST_F(BacktraceGuardedPoolAllocator, DoubleFree) { ASSERT_DEATH(DeallocateMemory2(GPA, Ptr), DeathRegex); } -TEST_F(BacktraceGuardedPoolAllocator, UseAfterFree) { +TEST_F(BacktraceGuardedPoolAllocatorDeathTest, UseAfterFree) { +#if defined(__linux__) && __ARM_ARCH == 7 + // Incomplete backtrace on Armv7 Linux + GTEST_SKIP(); +#endif + void *Ptr = AllocateMemory(GPA); DeallocateMemory(GPA, Ptr); diff --git a/gwp_asan/tests/enable_disable.cpp b/gwp_asan/tests/enable_disable.cpp index 2c6ba51..98da591 100644 --- a/gwp_asan/tests/enable_disable.cpp +++ b/gwp_asan/tests/enable_disable.cpp @@ -10,7 +10,7 @@ constexpr size_t Size = 100; -TEST_F(DefaultGuardedPoolAllocator, Fork) { +TEST_F(DefaultGuardedPoolAllocatorDeathTest, Fork) { void *P; pid_t Pid = fork(); EXPECT_GE(Pid, 0); diff --git a/gwp_asan/tests/harness.h b/gwp_asan/tests/harness.h index a61b856..ed91e64 100644 --- a/gwp_asan/tests/harness.h +++ b/gwp_asan/tests/harness.h @@ -106,4 +106,9 @@ protected: gwp_asan::GuardedPoolAllocator GPA; }; +// https://github.com/google/googletest/blob/master/docs/advanced.md#death-tests-and-threads +using DefaultGuardedPoolAllocatorDeathTest = DefaultGuardedPoolAllocator; +using CustomGuardedPoolAllocatorDeathTest = CustomGuardedPoolAllocator; +using BacktraceGuardedPoolAllocatorDeathTest = BacktraceGuardedPoolAllocator; + #endif // GWP_ASAN_TESTS_HARNESS_H_ |