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].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
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].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
TEST_F(CrashHandlerAPITest,PointerNotMine)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
TEST_F(CrashHandlerAPITest,PointerNotAllocated)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
TEST_F(CrashHandlerAPITest,DoubleFree)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
TEST_F(CrashHandlerAPITest,InvalidFree)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
TEST_F(CrashHandlerAPITest,InvalidFreeNoMetadata)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
TEST_F(CrashHandlerAPITest,UseAfterFree)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
TEST_F(CrashHandlerAPITest,BufferOverflow)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
TEST_F(CrashHandlerAPITest,BufferUnderflow)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