Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/gwp_asan/crash_handler.cpp
35236 views
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
//===----------------------------------------------------------------------===//
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
16
using AllocationMetadata = gwp_asan::AllocationMetadata;
17
using Error = gwp_asan::Error;
18
19
#ifdef __cplusplus
20
extern "C" {
21
#endif
22
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;
28
29
return ErrorPtr < State->GuardedPagePoolEnd &&
30
State->GuardedPagePool <= ErrorPtr;
31
}
32
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;
44
}
45
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)];
51
}
52
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;
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/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));
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
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;
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
107
uintptr_t __gwp_asan_get_allocation_address(
108
const gwp_asan::AllocationMetadata *AllocationMeta) {
109
return AllocationMeta->Addr;
110
}
111
112
size_t __gwp_asan_get_allocation_size(
113
const gwp_asan::AllocationMetadata *AllocationMeta) {
114
return AllocationMeta->RequestedSize;
115
}
116
117
uint64_t __gwp_asan_get_allocation_thread_id(
118
const gwp_asan::AllocationMetadata *AllocationMeta) {
119
return AllocationMeta->AllocationTrace.ThreadID;
120
}
121
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;
134
}
135
136
bool __gwp_asan_is_deallocated(
137
const gwp_asan::AllocationMetadata *AllocationMeta) {
138
return AllocationMeta->IsDeallocated;
139
}
140
141
uint64_t __gwp_asan_get_deallocation_thread_id(
142
const gwp_asan::AllocationMetadata *AllocationMeta) {
143
return AllocationMeta->DeallocationTrace.ThreadID;
144
}
145
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;
158
}
159
160
#ifdef __cplusplus
161
} // extern "C"
162
#endif
163
164