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