150
|
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
|
207
|
37 constexpr size_t AllocationMetadata::kStackFrameStorageBytes;
|
|
38 constexpr size_t AllocationMetadata::kMaxTraceLengthToCollect;
|
|
39
|
150
|
40 void AllocationMetadata::RecordAllocation(uintptr_t AllocAddr,
|
|
41 size_t AllocSize) {
|
|
42 Addr = AllocAddr;
|
207
|
43 RequestedSize = AllocSize;
|
150
|
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);
|
173
|
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;
|
150
|
70 TraceSize =
|
|
71 compression::pack(UncompressedBuffer, BacktraceLength, CompressedTrace,
|
|
72 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(this, Ptr);
|
|
102
|
|
103 if (Ptr % PageSize <= PageSize / 2)
|
|
104 return addrToSlot(this, Ptr - PageSize); // Round down.
|
|
105 return addrToSlot(this, Ptr + PageSize); // Round up.
|
|
106 }
|
|
107
|
|
108 } // namespace gwp_asan
|