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