Path: blob/main/contrib/llvm-project/compiler-rt/lib/gwp_asan/crash_handler.cpp
35236 views
//===-- crash_handler.cpp ---------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "gwp_asan/common.h"9#include "gwp_asan/stack_trace_compressor.h"1011#include <assert.h>12#include <stdint.h>13#include <string.h>1415using AllocationMetadata = gwp_asan::AllocationMetadata;16using Error = gwp_asan::Error;1718#ifdef __cplusplus19extern "C" {20#endif2122bool __gwp_asan_error_is_mine(const gwp_asan::AllocatorState *State,23uintptr_t ErrorPtr) {24assert(State && "State should not be nullptr.");25if (State->FailureType != Error::UNKNOWN && State->FailureAddress != 0)26return true;2728return ErrorPtr < State->GuardedPagePoolEnd &&29State->GuardedPagePool <= ErrorPtr;30}3132uintptr_t33__gwp_asan_get_internal_crash_address(const gwp_asan::AllocatorState *State,34uintptr_t ErrorPtr) {35// There can be a race between internally- and externally-raised faults. The36// fault address from the signal handler is used to discriminate whether it's37// internally- or externally-raised, and the pool maintains a special page at38// the end of the GuardedPagePool specifically for the internally-raised39// faults.40if (ErrorPtr != State->internallyDetectedErrorFaultAddress())41return 0u;42return State->FailureAddress;43}4445static const AllocationMetadata *46addrToMetadata(const gwp_asan::AllocatorState *State,47const AllocationMetadata *Metadata, uintptr_t Ptr) {48// Note - Similar implementation in guarded_pool_allocator.cpp.49return &Metadata[State->getNearestSlot(Ptr)];50}5152gwp_asan::Error53__gwp_asan_diagnose_error(const gwp_asan::AllocatorState *State,54const gwp_asan::AllocationMetadata *Metadata,55uintptr_t ErrorPtr) {56if (!__gwp_asan_error_is_mine(State, ErrorPtr))57return Error::UNKNOWN;5859if (State->FailureType != Error::UNKNOWN)60return State->FailureType;6162// Check for use-after-free.63if (addrToMetadata(State, Metadata, ErrorPtr)->IsDeallocated)64return Error::USE_AFTER_FREE;6566// Check for buffer-overflow. Because of allocation alignment or left/right67// page placement, we can have buffer-overflows that don't touch a guarded68// page, but these are not possible to detect unless it's also a69// use-after-free, which is handled above.70if (State->isGuardPage(ErrorPtr)) {71size_t Slot = State->getNearestSlot(ErrorPtr);72const AllocationMetadata *SlotMeta =73addrToMetadata(State, Metadata, State->slotToAddr(Slot));7475// Ensure that this slot was allocated once upon a time.76if (!SlotMeta->Addr)77return Error::UNKNOWN;7879if (SlotMeta->Addr < ErrorPtr)80return Error::BUFFER_OVERFLOW;81return Error::BUFFER_UNDERFLOW;82}8384// If we have reached here, the error is still unknown.85return Error::UNKNOWN;86}8788const gwp_asan::AllocationMetadata *89__gwp_asan_get_metadata(const gwp_asan::AllocatorState *State,90const gwp_asan::AllocationMetadata *Metadata,91uintptr_t ErrorPtr) {92if (!__gwp_asan_error_is_mine(State, ErrorPtr))93return nullptr;9495if (ErrorPtr >= State->GuardedPagePoolEnd ||96State->GuardedPagePool > ErrorPtr)97return nullptr;9899const AllocationMetadata *Meta = addrToMetadata(State, Metadata, ErrorPtr);100if (Meta->Addr == 0)101return nullptr;102103return Meta;104}105106uintptr_t __gwp_asan_get_allocation_address(107const gwp_asan::AllocationMetadata *AllocationMeta) {108return AllocationMeta->Addr;109}110111size_t __gwp_asan_get_allocation_size(112const gwp_asan::AllocationMetadata *AllocationMeta) {113return AllocationMeta->RequestedSize;114}115116uint64_t __gwp_asan_get_allocation_thread_id(117const gwp_asan::AllocationMetadata *AllocationMeta) {118return AllocationMeta->AllocationTrace.ThreadID;119}120121size_t __gwp_asan_get_allocation_trace(122const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,123size_t BufferLen) {124uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];125size_t UnpackedLength = gwp_asan::compression::unpack(126AllocationMeta->AllocationTrace.CompressedTrace,127AllocationMeta->AllocationTrace.TraceSize, UncompressedBuffer,128AllocationMetadata::kMaxTraceLengthToCollect);129if (UnpackedLength < BufferLen)130BufferLen = UnpackedLength;131memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));132return UnpackedLength;133}134135bool __gwp_asan_is_deallocated(136const gwp_asan::AllocationMetadata *AllocationMeta) {137return AllocationMeta->IsDeallocated;138}139140uint64_t __gwp_asan_get_deallocation_thread_id(141const gwp_asan::AllocationMetadata *AllocationMeta) {142return AllocationMeta->DeallocationTrace.ThreadID;143}144145size_t __gwp_asan_get_deallocation_trace(146const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,147size_t BufferLen) {148uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];149size_t UnpackedLength = gwp_asan::compression::unpack(150AllocationMeta->DeallocationTrace.CompressedTrace,151AllocationMeta->DeallocationTrace.TraceSize, UncompressedBuffer,152AllocationMetadata::kMaxTraceLengthToCollect);153if (UnpackedLength < BufferLen)154BufferLen = UnpackedLength;155memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));156return UnpackedLength;157}158159#ifdef __cplusplus160} // extern "C"161#endif162163164