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 void AllocationMetadata::RecordAllocation(uintptr_t AllocAddr, 38 size_t AllocSize) { 39 Addr = AllocAddr; 40 Size = AllocSize; 41 IsDeallocated = false; 42 43 AllocationTrace.ThreadID = getThreadID(); 44 DeallocationTrace.TraceSize = 0; 45 DeallocationTrace.ThreadID = kInvalidThreadID; 46 } 47 48 void AllocationMetadata::RecordDeallocation() { 49 IsDeallocated = true; 50 DeallocationTrace.ThreadID = getThreadID(); 51 } 52 53 void AllocationMetadata::CallSiteInfo::RecordBacktrace( 54 options::Backtrace_t Backtrace) { 55 TraceSize = 0; 56 if (!Backtrace) 57 return; 58 59 uintptr_t UncompressedBuffer[kMaxTraceLengthToCollect]; 60 size_t BacktraceLength = 61 Backtrace(UncompressedBuffer, kMaxTraceLengthToCollect); 62 TraceSize = 63 compression::pack(UncompressedBuffer, BacktraceLength, CompressedTrace, 64 AllocationMetadata::kStackFrameStorageBytes); 65 } 66 67 size_t AllocatorState::maximumAllocationSize() const { return PageSize; } 68 69 uintptr_t AllocatorState::slotToAddr(size_t N) const { 70 return GuardedPagePool + (PageSize * (1 + N)) + (maximumAllocationSize() * N); 71 } 72 73 bool AllocatorState::isGuardPage(uintptr_t Ptr) const { 74 assert(pointerIsMine(reinterpret_cast<void *>(Ptr))); 75 size_t PageOffsetFromPoolStart = (Ptr - GuardedPagePool) / PageSize; 76 size_t PagesPerSlot = maximumAllocationSize() / PageSize; 77 return (PageOffsetFromPoolStart % (PagesPerSlot + 1)) == 0; 78 } 79 80 static size_t addrToSlot(const AllocatorState *State, uintptr_t Ptr) { 81 size_t ByteOffsetFromPoolStart = Ptr - State->GuardedPagePool; 82 return ByteOffsetFromPoolStart / 83 (State->maximumAllocationSize() + State->PageSize); 84 } 85 86 size_t AllocatorState::getNearestSlot(uintptr_t Ptr) const { 87 if (Ptr <= GuardedPagePool + PageSize) 88 return 0; 89 if (Ptr > GuardedPagePoolEnd - PageSize) 90 return MaxSimultaneousAllocations - 1; 91 92 if (!isGuardPage(Ptr)) 93 return addrToSlot(this, Ptr); 94 95 if (Ptr % PageSize <= PageSize / 2) 96 return addrToSlot(this, Ptr - PageSize); // Round down. 97 return addrToSlot(this, Ptr + PageSize); // Round up. 98 } 99 100 } // namespace gwp_asan 101