summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-02-17 03:31:51 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-02-17 03:31:51 +0000
commit873935e24f28a742258dce0c488942416acae152 (patch)
tree1310d30a760d2309aeea9845a45dfe3f3f3633f9
parent154587cb48e6d6c569b69859e496a4467a65c576 (diff)
parent540563280a95233750aeaf2caa0f07450e1c24fd (diff)
downloadgwp_asan-873935e24f28a742258dce0c488942416acae152.tar.gz
Snap for 8191477 from 540563280a95233750aeaf2caa0f07450e1c24fd to tm-frc-resolv-release
Change-Id: I6d6572c95c7da996cb8c4db9311dd84006cafc76
-rw-r--r--Android.bp9
-rw-r--r--gwp_asan/common.h57
-rw-r--r--gwp_asan/guarded_pool_allocator.cpp12
-rwxr-xr-xgwp_asan/scripts/symbolize.sh8
-rw-r--r--gwp_asan/tests/alignment.cpp42
-rw-r--r--gwp_asan/tests/backtrace.cpp9
-rw-r--r--gwp_asan/tests/enable_disable.cpp2
-rw-r--r--gwp_asan/tests/harness.h5
8 files changed, 111 insertions, 33 deletions
diff --git a/Android.bp b/Android.bp
index 4b57e62..e45795f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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_