brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.5 KiB · 555365c Raw
163 lines · cpp
1//===-- crash_handler.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "gwp_asan/common.h"10#include "gwp_asan/stack_trace_compressor.h"11 12#include <assert.h>13#include <stdint.h>14#include <string.h>15 16using AllocationMetadata = gwp_asan::AllocationMetadata;17using Error = gwp_asan::Error;18 19#ifdef __cplusplus20extern "C" {21#endif22 23bool __gwp_asan_error_is_mine(const gwp_asan::AllocatorState *State,24                              uintptr_t ErrorPtr) {25  assert(State && "State should not be nullptr.");26  if (State->FailureType != Error::UNKNOWN && State->FailureAddress != 0)27    return true;28 29  return ErrorPtr < State->GuardedPagePoolEnd &&30         State->GuardedPagePool <= ErrorPtr;31}32 33uintptr_t34__gwp_asan_get_internal_crash_address(const gwp_asan::AllocatorState *State,35                                      uintptr_t ErrorPtr) {36  // There can be a race between internally- and externally-raised faults. The37  // fault address from the signal handler is used to discriminate whether it's38  // internally- or externally-raised, and the pool maintains a special page at39  // the end of the GuardedPagePool specifically for the internally-raised40  // faults.41  if (ErrorPtr != State->internallyDetectedErrorFaultAddress())42    return 0u;43  return State->FailureAddress;44}45 46static const AllocationMetadata *47addrToMetadata(const gwp_asan::AllocatorState *State,48               const AllocationMetadata *Metadata, uintptr_t Ptr) {49  // Note - Similar implementation in guarded_pool_allocator.cpp.50  return &Metadata[State->getNearestSlot(Ptr)];51}52 53gwp_asan::Error54__gwp_asan_diagnose_error(const gwp_asan::AllocatorState *State,55                          const gwp_asan::AllocationMetadata *Metadata,56                          uintptr_t ErrorPtr) {57  if (!__gwp_asan_error_is_mine(State, ErrorPtr))58    return Error::UNKNOWN;59 60  if (State->FailureType != Error::UNKNOWN)61    return State->FailureType;62 63  // Check for use-after-free.64  if (addrToMetadata(State, Metadata, ErrorPtr)->IsDeallocated)65    return Error::USE_AFTER_FREE;66 67  // Check for buffer-overflow. Because of allocation alignment or left/right68  // page placement, we can have buffer-overflows that don't touch a guarded69  // page, but these are not possible to detect unless it's also a70  // use-after-free, which is handled above.71  if (State->isGuardPage(ErrorPtr)) {72    size_t Slot = State->getNearestSlot(ErrorPtr);73    const AllocationMetadata *SlotMeta =74        addrToMetadata(State, Metadata, State->slotToAddr(Slot));75 76    // Ensure that this slot was allocated once upon a time.77    if (!SlotMeta->Addr)78      return Error::UNKNOWN;79 80    if (SlotMeta->Addr < ErrorPtr)81      return Error::BUFFER_OVERFLOW;82    return Error::BUFFER_UNDERFLOW;83  }84 85  // If we have reached here, the error is still unknown.86  return Error::UNKNOWN;87}88 89const gwp_asan::AllocationMetadata *90__gwp_asan_get_metadata(const gwp_asan::AllocatorState *State,91                        const gwp_asan::AllocationMetadata *Metadata,92                        uintptr_t ErrorPtr) {93  if (!__gwp_asan_error_is_mine(State, ErrorPtr))94    return nullptr;95 96  if (ErrorPtr >= State->GuardedPagePoolEnd ||97      State->GuardedPagePool > ErrorPtr)98    return nullptr;99 100  const AllocationMetadata *Meta = addrToMetadata(State, Metadata, ErrorPtr);101  if (Meta->Addr == 0)102    return nullptr;103 104  return Meta;105}106 107uintptr_t __gwp_asan_get_allocation_address(108    const gwp_asan::AllocationMetadata *AllocationMeta) {109  return AllocationMeta->Addr;110}111 112size_t __gwp_asan_get_allocation_size(113    const gwp_asan::AllocationMetadata *AllocationMeta) {114  return AllocationMeta->RequestedSize;115}116 117uint64_t __gwp_asan_get_allocation_thread_id(118    const gwp_asan::AllocationMetadata *AllocationMeta) {119  return AllocationMeta->AllocationTrace.ThreadID;120}121 122size_t __gwp_asan_get_allocation_trace(123    const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,124    size_t BufferLen) {125  uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];126  size_t UnpackedLength = gwp_asan::compression::unpack(127      AllocationMeta->AllocationTrace.CompressedTrace,128      AllocationMeta->AllocationTrace.TraceSize, UncompressedBuffer,129      AllocationMetadata::kMaxTraceLengthToCollect);130  if (UnpackedLength < BufferLen)131    BufferLen = UnpackedLength;132  memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));133  return UnpackedLength;134}135 136bool __gwp_asan_is_deallocated(137    const gwp_asan::AllocationMetadata *AllocationMeta) {138  return AllocationMeta->IsDeallocated;139}140 141uint64_t __gwp_asan_get_deallocation_thread_id(142    const gwp_asan::AllocationMetadata *AllocationMeta) {143  return AllocationMeta->DeallocationTrace.ThreadID;144}145 146size_t __gwp_asan_get_deallocation_trace(147    const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,148    size_t BufferLen) {149  uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];150  size_t UnpackedLength = gwp_asan::compression::unpack(151      AllocationMeta->DeallocationTrace.CompressedTrace,152      AllocationMeta->DeallocationTrace.TraceSize, UncompressedBuffer,153      AllocationMetadata::kMaxTraceLengthToCollect);154  if (UnpackedLength < BufferLen)155    BufferLen = UnpackedLength;156  memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));157  return UnpackedLength;158}159 160#ifdef __cplusplus161} // extern "C"162#endif163