1*e8d8bef9SDimitry Andric //===-- crash_handler.cpp ---------------------------------------*- C++ -*-===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric 95ffd83dbSDimitry Andric #include "gwp_asan/common.h" 105ffd83dbSDimitry Andric #include "gwp_asan/stack_trace_compressor.h" 115ffd83dbSDimitry Andric 125ffd83dbSDimitry Andric #include <assert.h> 13*e8d8bef9SDimitry Andric #include <stdint.h> 14*e8d8bef9SDimitry Andric #include <string.h> 155ffd83dbSDimitry Andric 165ffd83dbSDimitry Andric using AllocationMetadata = gwp_asan::AllocationMetadata; 175ffd83dbSDimitry Andric using Error = gwp_asan::Error; 185ffd83dbSDimitry Andric 195ffd83dbSDimitry Andric #ifdef __cplusplus 205ffd83dbSDimitry Andric extern "C" { 215ffd83dbSDimitry Andric #endif 225ffd83dbSDimitry Andric 235ffd83dbSDimitry Andric bool __gwp_asan_error_is_mine(const gwp_asan::AllocatorState *State, 245ffd83dbSDimitry Andric uintptr_t ErrorPtr) { 255ffd83dbSDimitry Andric assert(State && "State should not be nullptr."); 265ffd83dbSDimitry Andric if (State->FailureType != Error::UNKNOWN && State->FailureAddress != 0) 275ffd83dbSDimitry Andric return true; 285ffd83dbSDimitry Andric 295ffd83dbSDimitry Andric return ErrorPtr < State->GuardedPagePoolEnd && 305ffd83dbSDimitry Andric State->GuardedPagePool <= ErrorPtr; 315ffd83dbSDimitry Andric } 325ffd83dbSDimitry Andric 335ffd83dbSDimitry Andric uintptr_t 345ffd83dbSDimitry Andric __gwp_asan_get_internal_crash_address(const gwp_asan::AllocatorState *State) { 355ffd83dbSDimitry Andric return State->FailureAddress; 365ffd83dbSDimitry Andric } 375ffd83dbSDimitry Andric 385ffd83dbSDimitry Andric static const AllocationMetadata * 395ffd83dbSDimitry Andric addrToMetadata(const gwp_asan::AllocatorState *State, 405ffd83dbSDimitry Andric const AllocationMetadata *Metadata, uintptr_t Ptr) { 415ffd83dbSDimitry Andric // Note - Similar implementation in guarded_pool_allocator.cpp. 425ffd83dbSDimitry Andric return &Metadata[State->getNearestSlot(Ptr)]; 435ffd83dbSDimitry Andric } 445ffd83dbSDimitry Andric 455ffd83dbSDimitry Andric gwp_asan::Error 465ffd83dbSDimitry Andric __gwp_asan_diagnose_error(const gwp_asan::AllocatorState *State, 475ffd83dbSDimitry Andric const gwp_asan::AllocationMetadata *Metadata, 485ffd83dbSDimitry Andric uintptr_t ErrorPtr) { 495ffd83dbSDimitry Andric if (!__gwp_asan_error_is_mine(State, ErrorPtr)) 505ffd83dbSDimitry Andric return Error::UNKNOWN; 515ffd83dbSDimitry Andric 525ffd83dbSDimitry Andric if (State->FailureType != Error::UNKNOWN) 535ffd83dbSDimitry Andric return State->FailureType; 545ffd83dbSDimitry Andric 555ffd83dbSDimitry Andric // Let's try and figure out what the source of this error is. 565ffd83dbSDimitry Andric if (State->isGuardPage(ErrorPtr)) { 575ffd83dbSDimitry Andric size_t Slot = State->getNearestSlot(ErrorPtr); 585ffd83dbSDimitry Andric const AllocationMetadata *SlotMeta = 595ffd83dbSDimitry Andric addrToMetadata(State, Metadata, State->slotToAddr(Slot)); 605ffd83dbSDimitry Andric 615ffd83dbSDimitry Andric // Ensure that this slot was allocated once upon a time. 625ffd83dbSDimitry Andric if (!SlotMeta->Addr) 635ffd83dbSDimitry Andric return Error::UNKNOWN; 645ffd83dbSDimitry Andric 655ffd83dbSDimitry Andric if (SlotMeta->Addr < ErrorPtr) 665ffd83dbSDimitry Andric return Error::BUFFER_OVERFLOW; 675ffd83dbSDimitry Andric return Error::BUFFER_UNDERFLOW; 685ffd83dbSDimitry Andric } 695ffd83dbSDimitry Andric 705ffd83dbSDimitry Andric // Access wasn't a guard page, check for use-after-free. 715ffd83dbSDimitry Andric const AllocationMetadata *SlotMeta = 725ffd83dbSDimitry Andric addrToMetadata(State, Metadata, ErrorPtr); 735ffd83dbSDimitry Andric if (SlotMeta->IsDeallocated) { 745ffd83dbSDimitry Andric return Error::USE_AFTER_FREE; 755ffd83dbSDimitry Andric } 765ffd83dbSDimitry Andric 775ffd83dbSDimitry Andric // If we have reached here, the error is still unknown. 785ffd83dbSDimitry Andric return Error::UNKNOWN; 795ffd83dbSDimitry Andric } 805ffd83dbSDimitry Andric 815ffd83dbSDimitry Andric const gwp_asan::AllocationMetadata * 825ffd83dbSDimitry Andric __gwp_asan_get_metadata(const gwp_asan::AllocatorState *State, 835ffd83dbSDimitry Andric const gwp_asan::AllocationMetadata *Metadata, 845ffd83dbSDimitry Andric uintptr_t ErrorPtr) { 855ffd83dbSDimitry Andric if (!__gwp_asan_error_is_mine(State, ErrorPtr)) 865ffd83dbSDimitry Andric return nullptr; 875ffd83dbSDimitry Andric 885ffd83dbSDimitry Andric if (ErrorPtr >= State->GuardedPagePoolEnd || 895ffd83dbSDimitry Andric State->GuardedPagePool > ErrorPtr) 905ffd83dbSDimitry Andric return nullptr; 915ffd83dbSDimitry Andric 925ffd83dbSDimitry Andric const AllocationMetadata *Meta = addrToMetadata(State, Metadata, ErrorPtr); 935ffd83dbSDimitry Andric if (Meta->Addr == 0) 945ffd83dbSDimitry Andric return nullptr; 955ffd83dbSDimitry Andric 965ffd83dbSDimitry Andric return Meta; 975ffd83dbSDimitry Andric } 985ffd83dbSDimitry Andric 995ffd83dbSDimitry Andric uintptr_t __gwp_asan_get_allocation_address( 1005ffd83dbSDimitry Andric const gwp_asan::AllocationMetadata *AllocationMeta) { 1015ffd83dbSDimitry Andric return AllocationMeta->Addr; 1025ffd83dbSDimitry Andric } 1035ffd83dbSDimitry Andric 1045ffd83dbSDimitry Andric size_t __gwp_asan_get_allocation_size( 1055ffd83dbSDimitry Andric const gwp_asan::AllocationMetadata *AllocationMeta) { 1065ffd83dbSDimitry Andric return AllocationMeta->Size; 1075ffd83dbSDimitry Andric } 1085ffd83dbSDimitry Andric 1095ffd83dbSDimitry Andric uint64_t __gwp_asan_get_allocation_thread_id( 1105ffd83dbSDimitry Andric const gwp_asan::AllocationMetadata *AllocationMeta) { 1115ffd83dbSDimitry Andric return AllocationMeta->AllocationTrace.ThreadID; 1125ffd83dbSDimitry Andric } 1135ffd83dbSDimitry Andric 1145ffd83dbSDimitry Andric size_t __gwp_asan_get_allocation_trace( 1155ffd83dbSDimitry Andric const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer, 1165ffd83dbSDimitry Andric size_t BufferLen) { 117*e8d8bef9SDimitry Andric uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect]; 118*e8d8bef9SDimitry Andric size_t UnpackedLength = gwp_asan::compression::unpack( 1195ffd83dbSDimitry Andric AllocationMeta->AllocationTrace.CompressedTrace, 120*e8d8bef9SDimitry Andric AllocationMeta->AllocationTrace.TraceSize, UncompressedBuffer, 121*e8d8bef9SDimitry Andric AllocationMetadata::kMaxTraceLengthToCollect); 122*e8d8bef9SDimitry Andric if (UnpackedLength < BufferLen) 123*e8d8bef9SDimitry Andric BufferLen = UnpackedLength; 124*e8d8bef9SDimitry Andric memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer)); 125*e8d8bef9SDimitry Andric return UnpackedLength; 1265ffd83dbSDimitry Andric } 1275ffd83dbSDimitry Andric 1285ffd83dbSDimitry Andric bool __gwp_asan_is_deallocated( 1295ffd83dbSDimitry Andric const gwp_asan::AllocationMetadata *AllocationMeta) { 1305ffd83dbSDimitry Andric return AllocationMeta->IsDeallocated; 1315ffd83dbSDimitry Andric } 1325ffd83dbSDimitry Andric 1335ffd83dbSDimitry Andric uint64_t __gwp_asan_get_deallocation_thread_id( 1345ffd83dbSDimitry Andric const gwp_asan::AllocationMetadata *AllocationMeta) { 1355ffd83dbSDimitry Andric return AllocationMeta->DeallocationTrace.ThreadID; 1365ffd83dbSDimitry Andric } 1375ffd83dbSDimitry Andric 1385ffd83dbSDimitry Andric size_t __gwp_asan_get_deallocation_trace( 1395ffd83dbSDimitry Andric const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer, 1405ffd83dbSDimitry Andric size_t BufferLen) { 141*e8d8bef9SDimitry Andric uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect]; 142*e8d8bef9SDimitry Andric size_t UnpackedLength = gwp_asan::compression::unpack( 1435ffd83dbSDimitry Andric AllocationMeta->DeallocationTrace.CompressedTrace, 144*e8d8bef9SDimitry Andric AllocationMeta->DeallocationTrace.TraceSize, UncompressedBuffer, 145*e8d8bef9SDimitry Andric AllocationMetadata::kMaxTraceLengthToCollect); 146*e8d8bef9SDimitry Andric if (UnpackedLength < BufferLen) 147*e8d8bef9SDimitry Andric BufferLen = UnpackedLength; 148*e8d8bef9SDimitry Andric memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer)); 149*e8d8bef9SDimitry Andric return UnpackedLength; 1505ffd83dbSDimitry Andric } 1515ffd83dbSDimitry Andric 1525ffd83dbSDimitry Andric #ifdef __cplusplus 1535ffd83dbSDimitry Andric } // extern "C" 1545ffd83dbSDimitry Andric #endif 155