xref: /openbsd-src/gnu/llvm/compiler-rt/lib/gwp_asan/tests/crash_handler_api.cpp (revision 1ad61ae0a79a724d2d3ec69e69c8e1d1ff6b53a0)
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