123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- //===-- crash_handler.cpp ---------------------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "gwp_asan/common.h"
- #include "gwp_asan/stack_trace_compressor.h"
- #include <assert.h>
- #include <stdint.h>
- #include <string.h>
- using AllocationMetadata = gwp_asan::AllocationMetadata;
- using Error = gwp_asan::Error;
- #ifdef __cplusplus
- extern "C" {
- #endif
- bool __gwp_asan_error_is_mine(const gwp_asan::AllocatorState *State,
- uintptr_t ErrorPtr) {
- assert(State && "State should not be nullptr.");
- if (State->FailureType != Error::UNKNOWN && State->FailureAddress != 0)
- return true;
- return ErrorPtr < State->GuardedPagePoolEnd &&
- State->GuardedPagePool <= ErrorPtr;
- }
- uintptr_t
- __gwp_asan_get_internal_crash_address(const gwp_asan::AllocatorState *State,
- uintptr_t ErrorPtr) {
- // There can be a race between internally- and externally-raised faults. The
- // fault address from the signal handler is used to discriminate whether it's
- // internally- or externally-raised, and the pool maintains a special page at
- // the end of the GuardedPagePool specifically for the internally-raised
- // faults.
- if (ErrorPtr != State->internallyDetectedErrorFaultAddress())
- return 0u;
- return State->FailureAddress;
- }
- static const AllocationMetadata *
- addrToMetadata(const gwp_asan::AllocatorState *State,
- const AllocationMetadata *Metadata, uintptr_t Ptr) {
- // Note - Similar implementation in guarded_pool_allocator.cpp.
- return &Metadata[State->getNearestSlot(Ptr)];
- }
- gwp_asan::Error
- __gwp_asan_diagnose_error(const gwp_asan::AllocatorState *State,
- const gwp_asan::AllocationMetadata *Metadata,
- uintptr_t ErrorPtr) {
- if (!__gwp_asan_error_is_mine(State, ErrorPtr))
- return Error::UNKNOWN;
- if (State->FailureType != Error::UNKNOWN)
- return State->FailureType;
- // Check for use-after-free.
- if (addrToMetadata(State, Metadata, ErrorPtr)->IsDeallocated)
- return Error::USE_AFTER_FREE;
- // Check for buffer-overflow. Because of allocation alignment or left/right
- // page placement, we can have buffer-overflows that don't touch a guarded
- // page, but these are not possible to detect unless it's also a
- // use-after-free, which is handled above.
- if (State->isGuardPage(ErrorPtr)) {
- size_t Slot = State->getNearestSlot(ErrorPtr);
- const AllocationMetadata *SlotMeta =
- addrToMetadata(State, Metadata, State->slotToAddr(Slot));
- // Ensure that this slot was allocated once upon a time.
- if (!SlotMeta->Addr)
- return Error::UNKNOWN;
- if (SlotMeta->Addr < ErrorPtr)
- return Error::BUFFER_OVERFLOW;
- return Error::BUFFER_UNDERFLOW;
- }
- // If we have reached here, the error is still unknown.
- return Error::UNKNOWN;
- }
- const gwp_asan::AllocationMetadata *
- __gwp_asan_get_metadata(const gwp_asan::AllocatorState *State,
- const gwp_asan::AllocationMetadata *Metadata,
- uintptr_t ErrorPtr) {
- if (!__gwp_asan_error_is_mine(State, ErrorPtr))
- return nullptr;
- if (ErrorPtr >= State->GuardedPagePoolEnd ||
- State->GuardedPagePool > ErrorPtr)
- return nullptr;
- const AllocationMetadata *Meta = addrToMetadata(State, Metadata, ErrorPtr);
- if (Meta->Addr == 0)
- return nullptr;
- return Meta;
- }
- uintptr_t __gwp_asan_get_allocation_address(
- const gwp_asan::AllocationMetadata *AllocationMeta) {
- return AllocationMeta->Addr;
- }
- size_t __gwp_asan_get_allocation_size(
- const gwp_asan::AllocationMetadata *AllocationMeta) {
- return AllocationMeta->RequestedSize;
- }
- uint64_t __gwp_asan_get_allocation_thread_id(
- const gwp_asan::AllocationMetadata *AllocationMeta) {
- return AllocationMeta->AllocationTrace.ThreadID;
- }
- size_t __gwp_asan_get_allocation_trace(
- const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
- size_t BufferLen) {
- uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];
- size_t UnpackedLength = gwp_asan::compression::unpack(
- AllocationMeta->AllocationTrace.CompressedTrace,
- AllocationMeta->AllocationTrace.TraceSize, UncompressedBuffer,
- AllocationMetadata::kMaxTraceLengthToCollect);
- if (UnpackedLength < BufferLen)
- BufferLen = UnpackedLength;
- memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));
- return UnpackedLength;
- }
- bool __gwp_asan_is_deallocated(
- const gwp_asan::AllocationMetadata *AllocationMeta) {
- return AllocationMeta->IsDeallocated;
- }
- uint64_t __gwp_asan_get_deallocation_thread_id(
- const gwp_asan::AllocationMetadata *AllocationMeta) {
- return AllocationMeta->DeallocationTrace.ThreadID;
- }
- size_t __gwp_asan_get_deallocation_trace(
- const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
- size_t BufferLen) {
- uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];
- size_t UnpackedLength = gwp_asan::compression::unpack(
- AllocationMeta->DeallocationTrace.CompressedTrace,
- AllocationMeta->DeallocationTrace.TraceSize, UncompressedBuffer,
- AllocationMetadata::kMaxTraceLengthToCollect);
- if (UnpackedLength < BufferLen)
- BufferLen = UnpackedLength;
- memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));
- return UnpackedLength;
- }
- #ifdef __cplusplus
- } // extern "C"
- #endif
|