1 //===-- crash_handler.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/common.h"
10 #include "gwp_asan/stack_trace_compressor.h"
11
12 #include <assert.h>
13 #include <stdint.h>
14 #include <string.h>
15
16 using AllocationMetadata = gwp_asan::AllocationMetadata;
17 using Error = gwp_asan::Error;
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
__gwp_asan_error_is_mine(const gwp_asan::AllocatorState * State,uintptr_t ErrorPtr)23 bool __gwp_asan_error_is_mine(const gwp_asan::AllocatorState *State,
24 uintptr_t ErrorPtr) {
25 assert(State && "State should not be nullptr.");
26 if (State->FailureType != Error::UNKNOWN && State->FailureAddress != 0)
27 return true;
28
29 return ErrorPtr < State->GuardedPagePoolEnd &&
30 State->GuardedPagePool <= ErrorPtr;
31 }
32
33 uintptr_t
__gwp_asan_get_internal_crash_address(const gwp_asan::AllocatorState * State)34 __gwp_asan_get_internal_crash_address(const gwp_asan::AllocatorState *State) {
35 return State->FailureAddress;
36 }
37
38 static const AllocationMetadata *
addrToMetadata(const gwp_asan::AllocatorState * State,const AllocationMetadata * Metadata,uintptr_t Ptr)39 addrToMetadata(const gwp_asan::AllocatorState *State,
40 const AllocationMetadata *Metadata, uintptr_t Ptr) {
41 // Note - Similar implementation in guarded_pool_allocator.cpp.
42 return &Metadata[State->getNearestSlot(Ptr)];
43 }
44
45 gwp_asan::Error
__gwp_asan_diagnose_error(const gwp_asan::AllocatorState * State,const gwp_asan::AllocationMetadata * Metadata,uintptr_t ErrorPtr)46 __gwp_asan_diagnose_error(const gwp_asan::AllocatorState *State,
47 const gwp_asan::AllocationMetadata *Metadata,
48 uintptr_t ErrorPtr) {
49 if (!__gwp_asan_error_is_mine(State, ErrorPtr))
50 return Error::UNKNOWN;
51
52 if (State->FailureType != Error::UNKNOWN)
53 return State->FailureType;
54
55 // Let's try and figure out what the source of this error is.
56 if (State->isGuardPage(ErrorPtr)) {
57 size_t Slot = State->getNearestSlot(ErrorPtr);
58 const AllocationMetadata *SlotMeta =
59 addrToMetadata(State, Metadata, State->slotToAddr(Slot));
60
61 // Ensure that this slot was allocated once upon a time.
62 if (!SlotMeta->Addr)
63 return Error::UNKNOWN;
64
65 if (SlotMeta->Addr < ErrorPtr)
66 return Error::BUFFER_OVERFLOW;
67 return Error::BUFFER_UNDERFLOW;
68 }
69
70 // Access wasn't a guard page, check for use-after-free.
71 const AllocationMetadata *SlotMeta =
72 addrToMetadata(State, Metadata, ErrorPtr);
73 if (SlotMeta->IsDeallocated) {
74 return Error::USE_AFTER_FREE;
75 }
76
77 // If we have reached here, the error is still unknown.
78 return Error::UNKNOWN;
79 }
80
81 const gwp_asan::AllocationMetadata *
__gwp_asan_get_metadata(const gwp_asan::AllocatorState * State,const gwp_asan::AllocationMetadata * Metadata,uintptr_t ErrorPtr)82 __gwp_asan_get_metadata(const gwp_asan::AllocatorState *State,
83 const gwp_asan::AllocationMetadata *Metadata,
84 uintptr_t ErrorPtr) {
85 if (!__gwp_asan_error_is_mine(State, ErrorPtr))
86 return nullptr;
87
88 if (ErrorPtr >= State->GuardedPagePoolEnd ||
89 State->GuardedPagePool > ErrorPtr)
90 return nullptr;
91
92 const AllocationMetadata *Meta = addrToMetadata(State, Metadata, ErrorPtr);
93 if (Meta->Addr == 0)
94 return nullptr;
95
96 return Meta;
97 }
98
__gwp_asan_get_allocation_address(const gwp_asan::AllocationMetadata * AllocationMeta)99 uintptr_t __gwp_asan_get_allocation_address(
100 const gwp_asan::AllocationMetadata *AllocationMeta) {
101 return AllocationMeta->Addr;
102 }
103
__gwp_asan_get_allocation_size(const gwp_asan::AllocationMetadata * AllocationMeta)104 size_t __gwp_asan_get_allocation_size(
105 const gwp_asan::AllocationMetadata *AllocationMeta) {
106 return AllocationMeta->RequestedSize;
107 }
108
__gwp_asan_get_allocation_thread_id(const gwp_asan::AllocationMetadata * AllocationMeta)109 uint64_t __gwp_asan_get_allocation_thread_id(
110 const gwp_asan::AllocationMetadata *AllocationMeta) {
111 return AllocationMeta->AllocationTrace.ThreadID;
112 }
113
__gwp_asan_get_allocation_trace(const gwp_asan::AllocationMetadata * AllocationMeta,uintptr_t * Buffer,size_t BufferLen)114 size_t __gwp_asan_get_allocation_trace(
115 const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
116 size_t BufferLen) {
117 uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];
118 size_t UnpackedLength = gwp_asan::compression::unpack(
119 AllocationMeta->AllocationTrace.CompressedTrace,
120 AllocationMeta->AllocationTrace.TraceSize, UncompressedBuffer,
121 AllocationMetadata::kMaxTraceLengthToCollect);
122 if (UnpackedLength < BufferLen)
123 BufferLen = UnpackedLength;
124 memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));
125 return UnpackedLength;
126 }
127
__gwp_asan_is_deallocated(const gwp_asan::AllocationMetadata * AllocationMeta)128 bool __gwp_asan_is_deallocated(
129 const gwp_asan::AllocationMetadata *AllocationMeta) {
130 return AllocationMeta->IsDeallocated;
131 }
132
__gwp_asan_get_deallocation_thread_id(const gwp_asan::AllocationMetadata * AllocationMeta)133 uint64_t __gwp_asan_get_deallocation_thread_id(
134 const gwp_asan::AllocationMetadata *AllocationMeta) {
135 return AllocationMeta->DeallocationTrace.ThreadID;
136 }
137
__gwp_asan_get_deallocation_trace(const gwp_asan::AllocationMetadata * AllocationMeta,uintptr_t * Buffer,size_t BufferLen)138 size_t __gwp_asan_get_deallocation_trace(
139 const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
140 size_t BufferLen) {
141 uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];
142 size_t UnpackedLength = gwp_asan::compression::unpack(
143 AllocationMeta->DeallocationTrace.CompressedTrace,
144 AllocationMeta->DeallocationTrace.TraceSize, UncompressedBuffer,
145 AllocationMetadata::kMaxTraceLengthToCollect);
146 if (UnpackedLength < BufferLen)
147 BufferLen = UnpackedLength;
148 memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));
149 return UnpackedLength;
150 }
151
152 #ifdef __cplusplus
153 } // extern "C"
154 #endif
155