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
14using Error = gwp_asan::Error;
15using GuardedPoolAllocator = gwp_asan::GuardedPoolAllocator;
16using AllocationMetadata = gwp_asan::AllocationMetadata;
17using AllocatorState = gwp_asan::AllocatorState;
18
19class CrashHandlerAPITest : public ::testing::Test {
20public:
21 void SetUp() override { setupState(); }
22
23protected:
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(Ptr: 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 Unpacked: BacktraceConstants, UnpackedSize: kNumBacktraceConstants,
52 Packed: Meta->AllocationTrace.CompressedTrace,
53 PackedMaxSize: AllocationMetadata::kStackFrameStorageBytes);
54
55 if (Meta->IsDeallocated)
56 Meta->DeallocationTrace.TraceSize = gwp_asan::compression::pack(
57 Unpacked: BacktraceConstants, UnpackedSize: kNumBacktraceConstants,
58 Packed: Meta->DeallocationTrace.CompressedTrace,
59 PackedMaxSize: 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 AllocationMeta: Meta, Buffer, BufferLen: 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(AllocationMeta: Meta, Buffer,
73 BufferLen: 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: &State, Metadata, ErrorPtr);
82 EXPECT_NE(nullptr, Meta);
83 EXPECT_EQ(Metadata[Index].Addr, __gwp_asan_get_allocation_address(AllocationMeta: Meta));
84 EXPECT_EQ(Metadata[Index].RequestedSize,
85 __gwp_asan_get_allocation_size(AllocationMeta: Meta));
86 EXPECT_EQ(Metadata[Index].AllocationTrace.ThreadID,
87 __gwp_asan_get_allocation_thread_id(AllocationMeta: Meta));
88
89 bool IsDeallocated = __gwp_asan_is_deallocated(AllocationMeta: 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(AllocationMeta: 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
107uintptr_t CrashHandlerAPITest::BacktraceConstants[kNumBacktraceConstants] = {
108 0xdeadbeef, 0xdeadc0de, 0xbadc0ffe, 0xcafef00d};
109
110TEST_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
124TEST_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
134TEST_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
150TEST_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
166TEST_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
180TEST_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
192TEST_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
204TEST_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

source code of compiler-rt/lib/gwp_asan/tests/crash_handler_api.cpp