1 //===-- crash_handler_api.cpp -----------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "gwp_asan/crash_handler.h" 10 #include "gwp_asan/guarded_pool_allocator.h" 11 #include "gwp_asan/stack_trace_compressor.h" 12 #include "gwp_asan/tests/harness.h" 13 14 using Error = gwp_asan::Error; 15 using GuardedPoolAllocator = gwp_asan::GuardedPoolAllocator; 16 using AllocationMetadata = gwp_asan::AllocationMetadata; 17 using AllocatorState = gwp_asan::AllocatorState; 18 19 class CrashHandlerAPITest : public ::testing::Test { 20 public: 21 void SetUp() override { setupState(); } 22 23 protected: 24 size_t metadata(uintptr_t Addr, uintptr_t Size, bool IsDeallocated) { 25 // Should only be allocating the 0x3000, 0x5000, 0x7000, 0x9000 pages. 26 EXPECT_GE(Addr, 0x3000u); 27 EXPECT_LT(Addr, 0xa000u); 28 29 size_t Slot = State.getNearestSlot(Addr); 30 31 Metadata[Slot].Addr = Addr; 32 Metadata[Slot].Size = Size; 33 Metadata[Slot].IsDeallocated = IsDeallocated; 34 Metadata[Slot].AllocationTrace.ThreadID = 123; 35 Metadata[Slot].DeallocationTrace.ThreadID = 321; 36 setupBacktraces(&Metadata[Slot]); 37 38 return Slot; 39 } 40 41 void setupState() { 42 State.GuardedPagePool = 0x2000; 43 State.GuardedPagePoolEnd = 0xb000; 44 State.MaxSimultaneousAllocations = 4; // 0x3000, 0x5000, 0x7000, 0x9000. 45 State.PageSize = 0x1000; 46 } 47 48 void setupBacktraces(AllocationMetadata *Meta) { 49 Meta->AllocationTrace.TraceSize = gwp_asan::compression::pack( 50 BacktraceConstants, kNumBacktraceConstants, 51 Meta->AllocationTrace.CompressedTrace, 52 AllocationMetadata::kStackFrameStorageBytes); 53 54 if (Meta->IsDeallocated) 55 Meta->DeallocationTrace.TraceSize = gwp_asan::compression::pack( 56 BacktraceConstants, kNumBacktraceConstants, 57 Meta->DeallocationTrace.CompressedTrace, 58 AllocationMetadata::kStackFrameStorageBytes); 59 } 60 61 void checkBacktrace(const AllocationMetadata *Meta, bool IsDeallocated) { 62 uintptr_t Buffer[kNumBacktraceConstants]; 63 size_t NumBacktraceConstants = kNumBacktraceConstants; 64 EXPECT_EQ(NumBacktraceConstants, __gwp_asan_get_allocation_trace( 65 Meta, Buffer, kNumBacktraceConstants)); 66 for (size_t i = 0; i < kNumBacktraceConstants; ++i) 67 EXPECT_EQ(Buffer[i], BacktraceConstants[i]); 68 69 if (IsDeallocated) { 70 EXPECT_EQ(NumBacktraceConstants, 71 __gwp_asan_get_deallocation_trace(Meta, Buffer, 72 kNumBacktraceConstants)); 73 for (size_t i = 0; i < kNumBacktraceConstants; ++i) 74 EXPECT_EQ(Buffer[i], BacktraceConstants[i]); 75 } 76 } 77 78 void checkMetadata(size_t Index, uintptr_t ErrorPtr) { 79 const AllocationMetadata *Meta = 80 __gwp_asan_get_metadata(&State, Metadata, ErrorPtr); 81 EXPECT_NE(nullptr, Meta); 82 EXPECT_EQ(Metadata[Index].Addr, __gwp_asan_get_allocation_address(Meta)); 83 EXPECT_EQ(Metadata[Index].Size, __gwp_asan_get_allocation_size(Meta)); 84 EXPECT_EQ(Metadata[Index].AllocationTrace.ThreadID, 85 __gwp_asan_get_allocation_thread_id(Meta)); 86 87 bool IsDeallocated = __gwp_asan_is_deallocated(Meta); 88 EXPECT_EQ(Metadata[Index].IsDeallocated, IsDeallocated); 89 checkBacktrace(Meta, IsDeallocated); 90 91 if (!IsDeallocated) 92 return; 93 94 EXPECT_EQ(Metadata[Index].DeallocationTrace.ThreadID, 95 __gwp_asan_get_deallocation_thread_id(Meta)); 96 } 97 98 static constexpr size_t kNumBacktraceConstants = 4; 99 static uintptr_t BacktraceConstants[kNumBacktraceConstants]; 100 AllocatorState State = {}; 101 AllocationMetadata Metadata[4] = {}; 102 }; 103 104 uintptr_t CrashHandlerAPITest::BacktraceConstants[kNumBacktraceConstants] = { 105 0xdeadbeef, 0xdeadc0de, 0xbadc0ffe, 0xcafef00d}; 106 107 TEST_F(CrashHandlerAPITest, PointerNotMine) { 108 uintptr_t UnknownPtr = reinterpret_cast<uintptr_t>(&State); 109 110 EXPECT_FALSE(__gwp_asan_error_is_mine(&State, 0)); 111 EXPECT_FALSE(__gwp_asan_error_is_mine(&State, UnknownPtr)); 112 113 EXPECT_EQ(Error::UNKNOWN, __gwp_asan_diagnose_error(&State, Metadata, 0)); 114 EXPECT_EQ(Error::UNKNOWN, 115 __gwp_asan_diagnose_error(&State, Metadata, UnknownPtr)); 116 117 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, 0)); 118 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, UnknownPtr)); 119 } 120 121 TEST_F(CrashHandlerAPITest, PointerNotAllocated) { 122 uintptr_t FailureAddress = 0x9000; 123 124 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 125 EXPECT_EQ(Error::UNKNOWN, 126 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 127 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State)); 128 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress)); 129 } 130 131 TEST_F(CrashHandlerAPITest, DoubleFree) { 132 size_t Index = 133 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true); 134 uintptr_t FailureAddress = 0x7000; 135 136 State.FailureType = Error::DOUBLE_FREE; 137 State.FailureAddress = FailureAddress; 138 139 EXPECT_TRUE(__gwp_asan_error_is_mine(&State)); 140 EXPECT_EQ(Error::DOUBLE_FREE, 141 __gwp_asan_diagnose_error(&State, Metadata, 0x0)); 142 EXPECT_EQ(FailureAddress, __gwp_asan_get_internal_crash_address(&State)); 143 checkMetadata(Index, FailureAddress); 144 } 145 146 TEST_F(CrashHandlerAPITest, InvalidFree) { 147 size_t Index = 148 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ false); 149 uintptr_t FailureAddress = 0x7001; 150 151 State.FailureType = Error::INVALID_FREE; 152 State.FailureAddress = FailureAddress; 153 154 EXPECT_TRUE(__gwp_asan_error_is_mine(&State)); 155 EXPECT_EQ(Error::INVALID_FREE, 156 __gwp_asan_diagnose_error(&State, Metadata, 0x0)); 157 EXPECT_EQ(FailureAddress, __gwp_asan_get_internal_crash_address(&State)); 158 checkMetadata(Index, FailureAddress); 159 } 160 161 TEST_F(CrashHandlerAPITest, InvalidFreeNoMetadata) { 162 uintptr_t FailureAddress = 0x7001; 163 164 State.FailureType = Error::INVALID_FREE; 165 State.FailureAddress = FailureAddress; 166 167 EXPECT_TRUE(__gwp_asan_error_is_mine(&State)); 168 EXPECT_EQ(Error::INVALID_FREE, 169 __gwp_asan_diagnose_error(&State, Metadata, 0x0)); 170 EXPECT_EQ(FailureAddress, __gwp_asan_get_internal_crash_address(&State)); 171 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress)); 172 } 173 174 TEST_F(CrashHandlerAPITest, UseAfterFree) { 175 size_t Index = 176 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true); 177 uintptr_t FailureAddress = 0x7001; 178 179 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 180 EXPECT_EQ(Error::USE_AFTER_FREE, 181 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 182 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State)); 183 checkMetadata(Index, FailureAddress); 184 } 185 186 TEST_F(CrashHandlerAPITest, BufferOverflow) { 187 size_t Index = 188 metadata(/* Addr */ 0x5f00, /* Size */ 0x100, /* IsDeallocated */ false); 189 uintptr_t FailureAddress = 0x6000; 190 191 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 192 EXPECT_EQ(Error::BUFFER_OVERFLOW, 193 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 194 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State)); 195 checkMetadata(Index, FailureAddress); 196 } 197 198 TEST_F(CrashHandlerAPITest, BufferUnderflow) { 199 size_t Index = 200 metadata(/* Addr */ 0x3000, /* Size */ 0x10, /* IsDeallocated*/ false); 201 uintptr_t FailureAddress = 0x2fff; 202 203 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 204 EXPECT_EQ(Error::BUFFER_UNDERFLOW, 205 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 206 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State)); 207 checkMetadata(Index, FailureAddress); 208 } 209