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