summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitch Phillips <31459023+hctim@users.noreply.github.com>2023-03-01 06:11:57 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-03-01 06:11:57 +0000
commit6c03df192783511601450ef71a54892c05cc674c (patch)
treeca0e77b2fa111814f842c6fa126448e156da2d92
parent6209dc9bc90cd5d1ae7c44145061173634ed21a5 (diff)
parent9951822be207b864b74d65f4078f87aa65e0bab2 (diff)
downloadgwp_asan-6c03df192783511601450ef71a54892c05cc674c.tar.gz
[GWP-ASan] Handle wild touches of the guarded pool. am: d58876b9d0 am: da07ca58e6 am: 54f6669aa2 am: b56bf6b79b am: 9951822be2
Original change: https://android-review.googlesource.com/c/platform/external/gwp_asan/+/2461753 Change-Id: I747358731df6d1bf22aa002c0e8b182cb2de9435 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--gwp_asan/optional/segv_handler_posix.cpp22
-rw-r--r--gwp_asan/tests/backtrace.cpp4
-rw-r--r--gwp_asan/tests/harness.cpp18
-rw-r--r--gwp_asan/tests/harness.h2
-rw-r--r--gwp_asan/tests/never_allocated.cpp55
-rw-r--r--gwp_asan/tests/recoverable.cpp13
6 files changed, 91 insertions, 23 deletions
diff --git a/gwp_asan/optional/segv_handler_posix.cpp b/gwp_asan/optional/segv_handler_posix.cpp
index e012963..198db5c 100644
--- a/gwp_asan/optional/segv_handler_posix.cpp
+++ b/gwp_asan/optional/segv_handler_posix.cpp
@@ -99,6 +99,12 @@ void printHeader(Error E, uintptr_t AccessPtr,
ThreadBuffer);
}
+static bool HasReportedBadPoolAccess = false;
+static const char *kUnknownCrashText =
+ "GWP-ASan cannot provide any more information about this error. This may "
+ "occur due to a wild memory access into the GWP-ASan pool, or an "
+ "overflow/underflow that is > 512B in length.\n";
+
void dumpReport(uintptr_t ErrorPtr, const gwp_asan::AllocatorState *State,
const gwp_asan::AllocationMetadata *Metadata,
SegvBacktrace_t SegvBacktrace, Printf_t Printf,
@@ -117,6 +123,15 @@ void dumpReport(uintptr_t ErrorPtr, const gwp_asan::AllocatorState *State,
const gwp_asan::AllocationMetadata *AllocMeta =
__gwp_asan_get_metadata(State, Metadata, ErrorPtr);
+ if (AllocMeta == nullptr) {
+ if (HasReportedBadPoolAccess) return;
+ HasReportedBadPoolAccess = true;
+ Printf("*** GWP-ASan detected a memory error ***\n");
+ ScopedEndOfReportDecorator Decorator(Printf);
+ Printf(kUnknownCrashText);
+ return;
+ }
+
// It's unusual for a signal handler to be invoked multiple times for the same
// allocation, but it's possible in various scenarios, like:
// 1. A double-free or invalid-free was invoked in one thread at the same
@@ -132,9 +147,7 @@ void dumpReport(uintptr_t ErrorPtr, const gwp_asan::AllocatorState *State,
Error E = __gwp_asan_diagnose_error(State, Metadata, ErrorPtr);
if (E == Error::UNKNOWN) {
- Printf("GWP-ASan cannot provide any more information about this error. "
- "This may occur due to a wild memory access into the GWP-ASan pool, "
- "or an overflow/underflow that is > 512B in length.\n");
+ Printf(kUnknownCrashText);
return;
}
@@ -149,9 +162,6 @@ void dumpReport(uintptr_t ErrorPtr, const gwp_asan::AllocatorState *State,
PrintBacktrace(Trace, TraceLength, Printf);
- if (AllocMeta == nullptr)
- return;
-
// Maybe print the deallocation trace.
if (__gwp_asan_is_deallocated(AllocMeta)) {
uint64_t ThreadID = __gwp_asan_get_deallocation_thread_id(AllocMeta);
diff --git a/gwp_asan/tests/backtrace.cpp b/gwp_asan/tests/backtrace.cpp
index e878994..7cbbcf5 100644
--- a/gwp_asan/tests/backtrace.cpp
+++ b/gwp_asan/tests/backtrace.cpp
@@ -68,10 +68,6 @@ TEST_P(BacktraceGuardedPoolAllocatorDeathTest, UseAfterFree) {
;
}
-INSTANTIATE_TEST_SUITE_P(RecoverableSignalDeathTest,
- BacktraceGuardedPoolAllocatorDeathTest,
- /* Recoverable */ testing::Bool());
-
TEST(Backtrace, Short) {
gwp_asan::AllocationMetadata Meta;
Meta.AllocationTrace.RecordBacktrace(
diff --git a/gwp_asan/tests/harness.cpp b/gwp_asan/tests/harness.cpp
index ccad80e..6d41630 100644
--- a/gwp_asan/tests/harness.cpp
+++ b/gwp_asan/tests/harness.cpp
@@ -8,6 +8,8 @@
#include "gwp_asan/tests/harness.h"
+#include <string>
+
namespace gwp_asan {
namespace test {
bool OnlyOnce() {
@@ -34,3 +36,19 @@ DeallocateMemory2(gwp_asan::GuardedPoolAllocator &GPA, void *Ptr) {
__attribute__((optnone)) void TouchMemory(void *Ptr) {
*(reinterpret_cast<volatile char *>(Ptr)) = 7;
}
+
+void CheckOnlyOneGwpAsanCrash(const std::string &OutputBuffer) {
+ const char *kGwpAsanErrorString = "GWP-ASan detected a memory error";
+ size_t FirstIndex = OutputBuffer.find(kGwpAsanErrorString);
+ ASSERT_NE(FirstIndex, std::string::npos) << "Didn't detect a GWP-ASan crash";
+ ASSERT_EQ(OutputBuffer.find(kGwpAsanErrorString, FirstIndex + 1),
+ std::string::npos)
+ << "Detected more than one GWP-ASan crash:\n"
+ << OutputBuffer;
+}
+
+INSTANTIATE_TEST_SUITE_P(RecoverableTests, BacktraceGuardedPoolAllocator,
+ /* Recoverable */ testing::Values(true));
+INSTANTIATE_TEST_SUITE_P(RecoverableAndNonRecoverableTests,
+ BacktraceGuardedPoolAllocatorDeathTest,
+ /* Recoverable */ testing::Bool());
diff --git a/gwp_asan/tests/harness.h b/gwp_asan/tests/harness.h
index c8f643d..89f4e11 100644
--- a/gwp_asan/tests/harness.h
+++ b/gwp_asan/tests/harness.h
@@ -46,6 +46,8 @@ void DeallocateMemory(gwp_asan::GuardedPoolAllocator &GPA, void *Ptr);
void DeallocateMemory2(gwp_asan::GuardedPoolAllocator &GPA, void *Ptr);
void TouchMemory(void *Ptr);
+void CheckOnlyOneGwpAsanCrash(const std::string &OutputBuffer);
+
class DefaultGuardedPoolAllocator : public Test {
public:
void SetUp() override {
diff --git a/gwp_asan/tests/never_allocated.cpp b/gwp_asan/tests/never_allocated.cpp
new file mode 100644
index 0000000..bd43b22
--- /dev/null
+++ b/gwp_asan/tests/never_allocated.cpp
@@ -0,0 +1,55 @@
+//===-- never_allocated.cpp -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <string>
+
+#include "gwp_asan/common.h"
+#include "gwp_asan/crash_handler.h"
+#include "gwp_asan/tests/harness.h"
+
+TEST_P(BacktraceGuardedPoolAllocatorDeathTest, NeverAllocated) {
+ SCOPED_TRACE("");
+ void *Ptr = GPA.allocate(0x1000);
+ GPA.deallocate(Ptr);
+
+ std::string DeathNeedle =
+ "GWP-ASan cannot provide any more information about this error";
+
+ // Trigger a guard page in a completely different slot that's never allocated.
+ // Previously, there was a bug that this would result in nullptr-dereference
+ // in the posix crash handler.
+ char *volatile NeverAllocatedPtr = static_cast<char *>(Ptr) + 0x3000;
+ if (!Recoverable) {
+ ASSERT_DEATH(*NeverAllocatedPtr = 0, DeathNeedle);
+ return;
+ }
+
+ *NeverAllocatedPtr = 0;
+ CheckOnlyOneGwpAsanCrash(GetOutputBuffer());
+ ASSERT_NE(std::string::npos, GetOutputBuffer().find(DeathNeedle));
+
+ // Check that subsequent invalid touches of the pool don't print a report.
+ GetOutputBuffer().clear();
+ for (size_t i = 0; i < 100; ++i) {
+ *NeverAllocatedPtr = 0;
+ *(NeverAllocatedPtr + 0x2000) = 0;
+ *(NeverAllocatedPtr + 0x3000) = 0;
+ ASSERT_TRUE(GetOutputBuffer().empty());
+ }
+
+ // Check that reports on the other slots still report a double-free, but only
+ // once.
+ GetOutputBuffer().clear();
+ GPA.deallocate(Ptr);
+ ASSERT_NE(std::string::npos, GetOutputBuffer().find("Double Free"));
+ GetOutputBuffer().clear();
+ for (size_t i = 0; i < 100; ++i) {
+ DeallocateMemory(GPA, Ptr);
+ ASSERT_TRUE(GetOutputBuffer().empty());
+ }
+}
diff --git a/gwp_asan/tests/recoverable.cpp b/gwp_asan/tests/recoverable.cpp
index adc9731..2c14ff5 100644
--- a/gwp_asan/tests/recoverable.cpp
+++ b/gwp_asan/tests/recoverable.cpp
@@ -17,16 +17,6 @@
#include "gwp_asan/crash_handler.h"
#include "gwp_asan/tests/harness.h"
-void CheckOnlyOneGwpAsanCrash(const std::string &OutputBuffer) {
- const char *kGwpAsanErrorString = "GWP-ASan detected a memory error";
- size_t FirstIndex = OutputBuffer.find(kGwpAsanErrorString);
- ASSERT_NE(FirstIndex, std::string::npos) << "Didn't detect a GWP-ASan crash";
- ASSERT_EQ(OutputBuffer.find(kGwpAsanErrorString, FirstIndex + 1),
- std::string::npos)
- << "Detected more than one GWP-ASan crash:\n"
- << OutputBuffer;
-}
-
TEST_P(BacktraceGuardedPoolAllocator, MultipleDoubleFreeOnlyOneOutput) {
SCOPED_TRACE("");
void *Ptr = AllocateMemory(GPA);
@@ -202,6 +192,3 @@ TEST_P(BacktraceGuardedPoolAllocator, InterThreadThrashingSingleAlloc) {
runInterThreadThrashingSingleAlloc(kNumIterations, &GPA);
CheckOnlyOneGwpAsanCrash(GetOutputBuffer());
}
-
-INSTANTIATE_TEST_SUITE_P(RecoverableTests, BacktraceGuardedPoolAllocator,
- /* Recoverable */ testing::Values(true));