xref: /llvm-project/compiler-rt/lib/gwp_asan/tests/crash_handler_api.cpp (revision a62586846fa90054bd9224912b07095d2fca662c)
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 ::testing::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].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 
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,
65               __gwp_asan_get_allocation_trace(&State, Meta, Buffer,
66                                               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(&State, Meta, Buffer,
73                                                   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, Metadata, ErrorPtr);
82     EXPECT_NE(nullptr, Meta);
83     EXPECT_EQ(Metadata[Index].Addr,
84               __gwp_asan_get_allocation_address(&State, Meta));
85     EXPECT_EQ(Metadata[Index].Size,
86               __gwp_asan_get_allocation_size(&State, Meta));
87     EXPECT_EQ(Metadata[Index].AllocationTrace.ThreadID,
88               __gwp_asan_get_allocation_thread_id(&State, Meta));
89 
90     bool IsDeallocated = __gwp_asan_is_deallocated(&State, Meta);
91     EXPECT_EQ(Metadata[Index].IsDeallocated, IsDeallocated);
92     checkBacktrace(Meta, IsDeallocated);
93 
94     if (!IsDeallocated)
95       return;
96 
97     EXPECT_EQ(Metadata[Index].DeallocationTrace.ThreadID,
98               __gwp_asan_get_deallocation_thread_id(&State, Meta));
99   }
100 
101   static constexpr size_t kNumBacktraceConstants = 4;
102   static uintptr_t BacktraceConstants[kNumBacktraceConstants];
103   AllocatorState State = {};
104   AllocationMetadata Metadata[4] = {};
105 };
106 
107 uintptr_t CrashHandlerAPITest::BacktraceConstants[kNumBacktraceConstants] = {
108     0xdeadbeef, 0xdeadc0de, 0xbadc0ffee, 0xcafef00d};
109 
110 TEST_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 
124 TEST_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));
131   EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress));
132 }
133 
134 TEST_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, __gwp_asan_get_internal_crash_address(&State));
146   checkMetadata(Index, FailureAddress);
147 }
148 
149 TEST_F(CrashHandlerAPITest, InvalidFree) {
150   size_t Index =
151       metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ false);
152   uintptr_t FailureAddress = 0x7001;
153 
154   State.FailureType = Error::INVALID_FREE;
155   State.FailureAddress = FailureAddress;
156 
157   EXPECT_TRUE(__gwp_asan_error_is_mine(&State));
158   EXPECT_EQ(Error::INVALID_FREE,
159             __gwp_asan_diagnose_error(&State, Metadata, 0x0));
160   EXPECT_EQ(FailureAddress, __gwp_asan_get_internal_crash_address(&State));
161   checkMetadata(Index, FailureAddress);
162 }
163 
164 TEST_F(CrashHandlerAPITest, InvalidFreeNoMetadata) {
165   uintptr_t FailureAddress = 0x7001;
166 
167   State.FailureType = Error::INVALID_FREE;
168   State.FailureAddress = FailureAddress;
169 
170   EXPECT_TRUE(__gwp_asan_error_is_mine(&State));
171   EXPECT_EQ(Error::INVALID_FREE,
172             __gwp_asan_diagnose_error(&State, Metadata, 0x0));
173   EXPECT_EQ(FailureAddress, __gwp_asan_get_internal_crash_address(&State));
174   EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress));
175 }
176 
177 TEST_F(CrashHandlerAPITest, UseAfterFree) {
178   size_t Index =
179       metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true);
180   uintptr_t FailureAddress = 0x7001;
181 
182   EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));
183   EXPECT_EQ(Error::USE_AFTER_FREE,
184             __gwp_asan_diagnose_error(&State, Metadata, FailureAddress));
185   EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State));
186   checkMetadata(Index, FailureAddress);
187 }
188 
189 TEST_F(CrashHandlerAPITest, BufferOverflow) {
190   size_t Index =
191       metadata(/* Addr */ 0x5f00, /* Size */ 0x100, /* IsDeallocated */ false);
192   uintptr_t FailureAddress = 0x6000;
193 
194   EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));
195   EXPECT_EQ(Error::BUFFER_OVERFLOW,
196             __gwp_asan_diagnose_error(&State, Metadata, FailureAddress));
197   EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State));
198   checkMetadata(Index, FailureAddress);
199 }
200 
201 TEST_F(CrashHandlerAPITest, BufferUnderflow) {
202   size_t Index =
203       metadata(/* Addr */ 0x3000, /* Size */ 0x10, /* IsDeallocated*/ false);
204   uintptr_t FailureAddress = 0x2fff;
205 
206   EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));
207   EXPECT_EQ(Error::BUFFER_UNDERFLOW,
208             __gwp_asan_diagnose_error(&State, Metadata, FailureAddress));
209   EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State));
210   checkMetadata(Index, FailureAddress);
211 }
212