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 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].RequestedSize = 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 = 0xc000; 44 InternalFaultAddr = State.GuardedPagePoolEnd - 0x10; 45 State.MaxSimultaneousAllocations = 4; // 0x3000, 0x5000, 0x7000, 0x9000. 46 State.PageSize = 0x1000; 47 } 48 49 void setupBacktraces(AllocationMetadata *Meta) { 50 Meta->AllocationTrace.TraceSize = gwp_asan::compression::pack( 51 BacktraceConstants, kNumBacktraceConstants, 52 Meta->AllocationTrace.CompressedTrace, 53 AllocationMetadata::kStackFrameStorageBytes); 54 55 if (Meta->IsDeallocated) 56 Meta->DeallocationTrace.TraceSize = gwp_asan::compression::pack( 57 BacktraceConstants, kNumBacktraceConstants, 58 Meta->DeallocationTrace.CompressedTrace, 59 AllocationMetadata::kStackFrameStorageBytes); 60 } 61 62 void checkBacktrace(const AllocationMetadata *Meta, bool IsDeallocated) { 63 uintptr_t Buffer[kNumBacktraceConstants]; 64 size_t NumBacktraceConstants = kNumBacktraceConstants; 65 EXPECT_EQ(NumBacktraceConstants, __gwp_asan_get_allocation_trace( 66 Meta, Buffer, kNumBacktraceConstants)); 67 for (size_t i = 0; i < kNumBacktraceConstants; ++i) 68 EXPECT_EQ(Buffer[i], BacktraceConstants[i]); 69 70 if (IsDeallocated) { 71 EXPECT_EQ(NumBacktraceConstants, 72 __gwp_asan_get_deallocation_trace(Meta, Buffer, 73 kNumBacktraceConstants)); 74 for (size_t i = 0; i < kNumBacktraceConstants; ++i) 75 EXPECT_EQ(Buffer[i], BacktraceConstants[i]); 76 } 77 } 78 79 void checkMetadata(size_t Index, uintptr_t ErrorPtr) { 80 const AllocationMetadata *Meta = 81 __gwp_asan_get_metadata(&State, Metadata, ErrorPtr); 82 EXPECT_NE(nullptr, Meta); 83 EXPECT_EQ(Metadata[Index].Addr, __gwp_asan_get_allocation_address(Meta)); 84 EXPECT_EQ(Metadata[Index].RequestedSize, 85 __gwp_asan_get_allocation_size(Meta)); 86 EXPECT_EQ(Metadata[Index].AllocationTrace.ThreadID, 87 __gwp_asan_get_allocation_thread_id(Meta)); 88 89 bool IsDeallocated = __gwp_asan_is_deallocated(Meta); 90 EXPECT_EQ(Metadata[Index].IsDeallocated, IsDeallocated); 91 checkBacktrace(Meta, IsDeallocated); 92 93 if (!IsDeallocated) 94 return; 95 96 EXPECT_EQ(Metadata[Index].DeallocationTrace.ThreadID, 97 __gwp_asan_get_deallocation_thread_id(Meta)); 98 } 99 100 static constexpr size_t kNumBacktraceConstants = 4; 101 static uintptr_t BacktraceConstants[kNumBacktraceConstants]; 102 AllocatorState State = {}; 103 AllocationMetadata Metadata[4] = {}; 104 uintptr_t InternalFaultAddr; 105 }; 106 107 uintptr_t CrashHandlerAPITest::BacktraceConstants[kNumBacktraceConstants] = { 108 0xdeadbeef, 0xdeadc0de, 0xbadc0ffe, 0xcafef00d}; 109 110 TEST_F(CrashHandlerAPITest, PointerNotMine) { 111 uintptr_t UnknownPtr = reinterpret_cast<uintptr_t>(&State); 112 113 EXPECT_FALSE(__gwp_asan_error_is_mine(&State, 0)); 114 EXPECT_FALSE(__gwp_asan_error_is_mine(&State, UnknownPtr)); 115 116 EXPECT_EQ(Error::UNKNOWN, __gwp_asan_diagnose_error(&State, Metadata, 0)); 117 EXPECT_EQ(Error::UNKNOWN, 118 __gwp_asan_diagnose_error(&State, Metadata, UnknownPtr)); 119 120 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, 0)); 121 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, UnknownPtr)); 122 } 123 124 TEST_F(CrashHandlerAPITest, PointerNotAllocated) { 125 uintptr_t FailureAddress = 0x9000; 126 127 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 128 EXPECT_EQ(Error::UNKNOWN, 129 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 130 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress)); 131 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress)); 132 } 133 134 TEST_F(CrashHandlerAPITest, DoubleFree) { 135 size_t Index = 136 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true); 137 uintptr_t FailureAddress = 0x7000; 138 139 State.FailureType = Error::DOUBLE_FREE; 140 State.FailureAddress = FailureAddress; 141 142 EXPECT_TRUE(__gwp_asan_error_is_mine(&State)); 143 EXPECT_EQ(Error::DOUBLE_FREE, 144 __gwp_asan_diagnose_error(&State, Metadata, 0x0)); 145 EXPECT_EQ(FailureAddress, 146 __gwp_asan_get_internal_crash_address(&State, InternalFaultAddr)); 147 checkMetadata(Index, FailureAddress); 148 } 149 150 TEST_F(CrashHandlerAPITest, InvalidFree) { 151 size_t Index = 152 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ false); 153 uintptr_t FailureAddress = 0x7001; 154 155 State.FailureType = Error::INVALID_FREE; 156 State.FailureAddress = FailureAddress; 157 158 EXPECT_TRUE(__gwp_asan_error_is_mine(&State)); 159 EXPECT_EQ(Error::INVALID_FREE, 160 __gwp_asan_diagnose_error(&State, Metadata, 0x0)); 161 EXPECT_EQ(FailureAddress, 162 __gwp_asan_get_internal_crash_address(&State, InternalFaultAddr)); 163 checkMetadata(Index, FailureAddress); 164 } 165 166 TEST_F(CrashHandlerAPITest, InvalidFreeNoMetadata) { 167 uintptr_t FailureAddress = 0x7001; 168 169 State.FailureType = Error::INVALID_FREE; 170 State.FailureAddress = FailureAddress; 171 172 EXPECT_TRUE(__gwp_asan_error_is_mine(&State)); 173 EXPECT_EQ(Error::INVALID_FREE, 174 __gwp_asan_diagnose_error(&State, Metadata, 0x0)); 175 EXPECT_EQ(FailureAddress, 176 __gwp_asan_get_internal_crash_address(&State, InternalFaultAddr)); 177 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress)); 178 } 179 180 TEST_F(CrashHandlerAPITest, UseAfterFree) { 181 size_t Index = 182 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true); 183 uintptr_t FailureAddress = 0x7001; 184 185 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 186 EXPECT_EQ(Error::USE_AFTER_FREE, 187 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 188 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress)); 189 checkMetadata(Index, FailureAddress); 190 } 191 192 TEST_F(CrashHandlerAPITest, BufferOverflow) { 193 size_t Index = 194 metadata(/* Addr */ 0x5f00, /* Size */ 0x100, /* IsDeallocated */ false); 195 uintptr_t FailureAddress = 0x6000; 196 197 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 198 EXPECT_EQ(Error::BUFFER_OVERFLOW, 199 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 200 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress)); 201 checkMetadata(Index, FailureAddress); 202 } 203 204 TEST_F(CrashHandlerAPITest, BufferUnderflow) { 205 size_t Index = 206 metadata(/* Addr */ 0x3000, /* Size */ 0x10, /* IsDeallocated*/ false); 207 uintptr_t FailureAddress = 0x2fff; 208 209 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 210 EXPECT_EQ(Error::BUFFER_UNDERFLOW, 211 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 212 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress)); 213 checkMetadata(Index, FailureAddress); 214 } 215