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