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 = 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].RequestedSize, 84 __gwp_asan_get_allocation_size(Meta)); 85 EXPECT_EQ(Metadata[Index].AllocationTrace.ThreadID, 86 __gwp_asan_get_allocation_thread_id(Meta)); 87 88 bool IsDeallocated = __gwp_asan_is_deallocated(Meta); 89 EXPECT_EQ(Metadata[Index].IsDeallocated, IsDeallocated); 90 checkBacktrace(Meta, IsDeallocated); 91 92 if (!IsDeallocated) 93 return; 94 95 EXPECT_EQ(Metadata[Index].DeallocationTrace.ThreadID, 96 __gwp_asan_get_deallocation_thread_id(Meta)); 97 } 98 99 static constexpr size_t kNumBacktraceConstants = 4; 100 static uintptr_t BacktraceConstants[kNumBacktraceConstants]; 101 AllocatorState State = {}; 102 AllocationMetadata Metadata[4] = {}; 103 }; 104 105 uintptr_t CrashHandlerAPITest::BacktraceConstants[kNumBacktraceConstants] = { 106 0xdeadbeef, 0xdeadc0de, 0xbadc0ffe, 0xcafef00d}; 107 108 TEST_F(CrashHandlerAPITest, PointerNotMine) { 109 uintptr_t UnknownPtr = reinterpret_cast<uintptr_t>(&State); 110 111 EXPECT_FALSE(__gwp_asan_error_is_mine(&State, 0)); 112 EXPECT_FALSE(__gwp_asan_error_is_mine(&State, UnknownPtr)); 113 114 EXPECT_EQ(Error::UNKNOWN, __gwp_asan_diagnose_error(&State, Metadata, 0)); 115 EXPECT_EQ(Error::UNKNOWN, 116 __gwp_asan_diagnose_error(&State, Metadata, UnknownPtr)); 117 118 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, 0)); 119 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, UnknownPtr)); 120 } 121 122 TEST_F(CrashHandlerAPITest, PointerNotAllocated) { 123 uintptr_t FailureAddress = 0x9000; 124 125 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 126 EXPECT_EQ(Error::UNKNOWN, 127 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 128 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State)); 129 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress)); 130 } 131 132 TEST_F(CrashHandlerAPITest, DoubleFree) { 133 size_t Index = 134 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true); 135 uintptr_t FailureAddress = 0x7000; 136 137 State.FailureType = Error::DOUBLE_FREE; 138 State.FailureAddress = FailureAddress; 139 140 EXPECT_TRUE(__gwp_asan_error_is_mine(&State)); 141 EXPECT_EQ(Error::DOUBLE_FREE, 142 __gwp_asan_diagnose_error(&State, Metadata, 0x0)); 143 EXPECT_EQ(FailureAddress, __gwp_asan_get_internal_crash_address(&State)); 144 checkMetadata(Index, FailureAddress); 145 } 146 147 TEST_F(CrashHandlerAPITest, InvalidFree) { 148 size_t Index = 149 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ false); 150 uintptr_t FailureAddress = 0x7001; 151 152 State.FailureType = Error::INVALID_FREE; 153 State.FailureAddress = FailureAddress; 154 155 EXPECT_TRUE(__gwp_asan_error_is_mine(&State)); 156 EXPECT_EQ(Error::INVALID_FREE, 157 __gwp_asan_diagnose_error(&State, Metadata, 0x0)); 158 EXPECT_EQ(FailureAddress, __gwp_asan_get_internal_crash_address(&State)); 159 checkMetadata(Index, FailureAddress); 160 } 161 162 TEST_F(CrashHandlerAPITest, InvalidFreeNoMetadata) { 163 uintptr_t FailureAddress = 0x7001; 164 165 State.FailureType = Error::INVALID_FREE; 166 State.FailureAddress = FailureAddress; 167 168 EXPECT_TRUE(__gwp_asan_error_is_mine(&State)); 169 EXPECT_EQ(Error::INVALID_FREE, 170 __gwp_asan_diagnose_error(&State, Metadata, 0x0)); 171 EXPECT_EQ(FailureAddress, __gwp_asan_get_internal_crash_address(&State)); 172 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress)); 173 } 174 175 TEST_F(CrashHandlerAPITest, UseAfterFree) { 176 size_t Index = 177 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true); 178 uintptr_t FailureAddress = 0x7001; 179 180 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 181 EXPECT_EQ(Error::USE_AFTER_FREE, 182 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 183 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State)); 184 checkMetadata(Index, FailureAddress); 185 } 186 187 TEST_F(CrashHandlerAPITest, BufferOverflow) { 188 size_t Index = 189 metadata(/* Addr */ 0x5f00, /* Size */ 0x100, /* IsDeallocated */ false); 190 uintptr_t FailureAddress = 0x6000; 191 192 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 193 EXPECT_EQ(Error::BUFFER_OVERFLOW, 194 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 195 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State)); 196 checkMetadata(Index, FailureAddress); 197 } 198 199 TEST_F(CrashHandlerAPITest, BufferUnderflow) { 200 size_t Index = 201 metadata(/* Addr */ 0x3000, /* Size */ 0x10, /* IsDeallocated*/ false); 202 uintptr_t FailureAddress = 0x2fff; 203 204 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress)); 205 EXPECT_EQ(Error::BUFFER_UNDERFLOW, 206 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress)); 207 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State)); 208 checkMetadata(Index, FailureAddress); 209 } 210