1 | //===-- common.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 | |
14 | using AllocationMetadata = gwp_asan::AllocationMetadata; |
15 | using Error = gwp_asan::Error; |
16 | |
17 | namespace gwp_asan { |
18 | |
19 | const char *ErrorToString(const Error &E) { |
20 | switch (E) { |
21 | case Error::UNKNOWN: |
22 | return "Unknown" ; |
23 | case Error::USE_AFTER_FREE: |
24 | return "Use After Free" ; |
25 | case Error::DOUBLE_FREE: |
26 | return "Double Free" ; |
27 | case Error::INVALID_FREE: |
28 | return "Invalid (Wild) Free" ; |
29 | case Error::BUFFER_OVERFLOW: |
30 | return "Buffer Overflow" ; |
31 | case Error::BUFFER_UNDERFLOW: |
32 | return "Buffer Underflow" ; |
33 | } |
34 | __builtin_trap(); |
35 | } |
36 | |
37 | constexpr size_t AllocationMetadata::kStackFrameStorageBytes; |
38 | constexpr size_t AllocationMetadata::kMaxTraceLengthToCollect; |
39 | |
40 | void AllocationMetadata::RecordAllocation(uintptr_t AllocAddr, |
41 | size_t AllocSize) { |
42 | Addr = AllocAddr; |
43 | RequestedSize = AllocSize; |
44 | IsDeallocated = false; |
45 | |
46 | AllocationTrace.ThreadID = getThreadID(); |
47 | DeallocationTrace.TraceSize = 0; |
48 | DeallocationTrace.ThreadID = kInvalidThreadID; |
49 | } |
50 | |
51 | void AllocationMetadata::RecordDeallocation() { |
52 | IsDeallocated = true; |
53 | DeallocationTrace.ThreadID = getThreadID(); |
54 | } |
55 | |
56 | void AllocationMetadata::CallSiteInfo::RecordBacktrace( |
57 | options::Backtrace_t Backtrace) { |
58 | TraceSize = 0; |
59 | if (!Backtrace) |
60 | return; |
61 | |
62 | uintptr_t UncompressedBuffer[kMaxTraceLengthToCollect]; |
63 | size_t BacktraceLength = |
64 | Backtrace(UncompressedBuffer, kMaxTraceLengthToCollect); |
65 | // Backtrace() returns the number of available frames, which may be greater |
66 | // than the number of frames in the buffer. In this case, we need to only pack |
67 | // the number of frames that are in the buffer. |
68 | if (BacktraceLength > kMaxTraceLengthToCollect) |
69 | BacktraceLength = kMaxTraceLengthToCollect; |
70 | TraceSize = |
71 | compression::pack(Unpacked: UncompressedBuffer, UnpackedSize: BacktraceLength, Packed: CompressedTrace, |
72 | PackedMaxSize: AllocationMetadata::kStackFrameStorageBytes); |
73 | } |
74 | |
75 | size_t AllocatorState::maximumAllocationSize() const { return PageSize; } |
76 | |
77 | uintptr_t AllocatorState::slotToAddr(size_t N) const { |
78 | return GuardedPagePool + (PageSize * (1 + N)) + (maximumAllocationSize() * N); |
79 | } |
80 | |
81 | bool AllocatorState::isGuardPage(uintptr_t Ptr) const { |
82 | assert(pointerIsMine(reinterpret_cast<void *>(Ptr))); |
83 | size_t PageOffsetFromPoolStart = (Ptr - GuardedPagePool) / PageSize; |
84 | size_t PagesPerSlot = maximumAllocationSize() / PageSize; |
85 | return (PageOffsetFromPoolStart % (PagesPerSlot + 1)) == 0; |
86 | } |
87 | |
88 | static size_t addrToSlot(const AllocatorState *State, uintptr_t Ptr) { |
89 | size_t ByteOffsetFromPoolStart = Ptr - State->GuardedPagePool; |
90 | return ByteOffsetFromPoolStart / |
91 | (State->maximumAllocationSize() + State->PageSize); |
92 | } |
93 | |
94 | size_t AllocatorState::getNearestSlot(uintptr_t Ptr) const { |
95 | if (Ptr <= GuardedPagePool + PageSize) |
96 | return 0; |
97 | if (Ptr > GuardedPagePoolEnd - PageSize) |
98 | return MaxSimultaneousAllocations - 1; |
99 | |
100 | if (!isGuardPage(Ptr)) |
101 | return addrToSlot(State: this, Ptr); |
102 | |
103 | if (Ptr % PageSize <= PageSize / 2) |
104 | return addrToSlot(State: this, Ptr: Ptr - PageSize); // Round down. |
105 | return addrToSlot(State: this, Ptr: Ptr + PageSize); // Round up. |
106 | } |
107 | |
108 | uintptr_t AllocatorState::internallyDetectedErrorFaultAddress() const { |
109 | return GuardedPagePoolEnd - 0x10; |
110 | } |
111 | |
112 | } // namespace gwp_asan |
113 | |