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:
SetUp()21 void SetUp() override { setupState(); }
22
23 protected:
metadata(uintptr_t Addr,uintptr_t Size,bool IsDeallocated)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
setupState()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
setupBacktraces(AllocationMetadata * Meta)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
checkBacktrace(const AllocationMetadata * Meta,bool IsDeallocated)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
checkMetadata(size_t Index,uintptr_t ErrorPtr)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
TEST_F(CrashHandlerAPITest,PointerNotMine)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
TEST_F(CrashHandlerAPITest,PointerNotAllocated)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
TEST_F(CrashHandlerAPITest,DoubleFree)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
TEST_F(CrashHandlerAPITest,InvalidFree)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
TEST_F(CrashHandlerAPITest,InvalidFreeNoMetadata)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
TEST_F(CrashHandlerAPITest,UseAfterFree)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
TEST_F(CrashHandlerAPITest,BufferOverflow)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
TEST_F(CrashHandlerAPITest,BufferUnderflow)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