xref: /freebsd/contrib/llvm-project/compiler-rt/lib/gwp_asan/common.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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  
ErrorToString(const Error & E)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  
RecordAllocation(uintptr_t AllocAddr,size_t AllocSize)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  
RecordDeallocation()51  void AllocationMetadata::RecordDeallocation() {
52    IsDeallocated = true;
53    DeallocationTrace.ThreadID = getThreadID();
54  }
55  
RecordBacktrace(options::Backtrace_t Backtrace)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(UncompressedBuffer, BacktraceLength, CompressedTrace,
72                          AllocationMetadata::kStackFrameStorageBytes);
73  }
74  
maximumAllocationSize() const75  size_t AllocatorState::maximumAllocationSize() const { return PageSize; }
76  
slotToAddr(size_t N) const77  uintptr_t AllocatorState::slotToAddr(size_t N) const {
78    return GuardedPagePool + (PageSize * (1 + N)) + (maximumAllocationSize() * N);
79  }
80  
isGuardPage(uintptr_t Ptr) const81  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  
addrToSlot(const AllocatorState * State,uintptr_t Ptr)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  
getNearestSlot(uintptr_t Ptr) const94  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  
internallyDetectedErrorFaultAddress() const108  uintptr_t AllocatorState::internallyDetectedErrorFaultAddress() const {
109    return GuardedPagePoolEnd - 0x10;
110  }
111  
112  } // namespace gwp_asan
113