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