[Clang][SME2] Enable multi-vector loads & stores for SME2 (#75821)
[llvm-project.git] / compiler-rt / lib / gwp_asan / crash_handler.cpp
blob555365c6e6f4d27eb6c041691a4a4eecdd057989
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-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "gwp_asan/common.h"
10 #include "gwp_asan/stack_trace_compressor.h"
12 #include <assert.h>
13 #include <stdint.h>
14 #include <string.h>
16 using AllocationMetadata = gwp_asan::AllocationMetadata;
17 using Error = gwp_asan::Error;
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
23 bool __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;
29 return ErrorPtr < State->GuardedPagePoolEnd &&
30 State->GuardedPagePool <= ErrorPtr;
33 uintptr_t
34 __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. The
37 // fault address from the signal handler is used to discriminate whether it's
38 // internally- or externally-raised, and the pool maintains a special page at
39 // the end of the GuardedPagePool specifically for the internally-raised
40 // faults.
41 if (ErrorPtr != State->internallyDetectedErrorFaultAddress())
42 return 0u;
43 return State->FailureAddress;
46 static const AllocationMetadata *
47 addrToMetadata(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)];
53 gwp_asan::Error
54 __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;
60 if (State->FailureType != Error::UNKNOWN)
61 return State->FailureType;
63 // Check for use-after-free.
64 if (addrToMetadata(State, Metadata, ErrorPtr)->IsDeallocated)
65 return Error::USE_AFTER_FREE;
67 // Check for buffer-overflow. Because of allocation alignment or left/right
68 // page placement, we can have buffer-overflows that don't touch a guarded
69 // page, but these are not possible to detect unless it's also a
70 // 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));
76 // Ensure that this slot was allocated once upon a time.
77 if (!SlotMeta->Addr)
78 return Error::UNKNOWN;
80 if (SlotMeta->Addr < ErrorPtr)
81 return Error::BUFFER_OVERFLOW;
82 return Error::BUFFER_UNDERFLOW;
85 // If we have reached here, the error is still unknown.
86 return Error::UNKNOWN;
89 const 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;
96 if (ErrorPtr >= State->GuardedPagePoolEnd ||
97 State->GuardedPagePool > ErrorPtr)
98 return nullptr;
100 const AllocationMetadata *Meta = addrToMetadata(State, Metadata, ErrorPtr);
101 if (Meta->Addr == 0)
102 return nullptr;
104 return Meta;
107 uintptr_t __gwp_asan_get_allocation_address(
108 const gwp_asan::AllocationMetadata *AllocationMeta) {
109 return AllocationMeta->Addr;
112 size_t __gwp_asan_get_allocation_size(
113 const gwp_asan::AllocationMetadata *AllocationMeta) {
114 return AllocationMeta->RequestedSize;
117 uint64_t __gwp_asan_get_allocation_thread_id(
118 const gwp_asan::AllocationMetadata *AllocationMeta) {
119 return AllocationMeta->AllocationTrace.ThreadID;
122 size_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;
136 bool __gwp_asan_is_deallocated(
137 const gwp_asan::AllocationMetadata *AllocationMeta) {
138 return AllocationMeta->IsDeallocated;
141 uint64_t __gwp_asan_get_deallocation_thread_id(
142 const gwp_asan::AllocationMetadata *AllocationMeta) {
143 return AllocationMeta->DeallocationTrace.ThreadID;
146 size_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;
160 #ifdef __cplusplus
161 } // extern "C"
162 #endif