113 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "gwp_asan/common.h"10#include "gwp_asan/stack_trace_compressor.h"11 12#include <assert.h>13 14using AllocationMetadata = gwp_asan::AllocationMetadata;15using Error = gwp_asan::Error;16 17namespace gwp_asan {18 19const 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 37constexpr size_t AllocationMetadata::kStackFrameStorageBytes;38constexpr size_t AllocationMetadata::kMaxTraceLengthToCollect;39 40void 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 51void AllocationMetadata::RecordDeallocation() {52 IsDeallocated = true;53 DeallocationTrace.ThreadID = getThreadID();54}55 56void 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 greater66 // than the number of frames in the buffer. In this case, we need to only pack67 // 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 75size_t AllocatorState::maximumAllocationSize() const { return PageSize; }76 77uintptr_t AllocatorState::slotToAddr(size_t N) const {78 return GuardedPagePool + (PageSize * (1 + N)) + (maximumAllocationSize() * N);79}80 81bool 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 88static 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 94size_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 108uintptr_t AllocatorState::internallyDetectedErrorFaultAddress() const {109 return GuardedPagePoolEnd - 0x10;110}111 112} // namespace gwp_asan113