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