15ffd83dbSDimitry Andric //===-- common.cpp ----------------------------------------------*- C++ -*-===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric 95ffd83dbSDimitry Andric #include "gwp_asan/common.h" 105ffd83dbSDimitry Andric #include "gwp_asan/stack_trace_compressor.h" 115ffd83dbSDimitry Andric 125ffd83dbSDimitry Andric #include <assert.h> 135ffd83dbSDimitry Andric 145ffd83dbSDimitry Andric using AllocationMetadata = gwp_asan::AllocationMetadata; 155ffd83dbSDimitry Andric using Error = gwp_asan::Error; 165ffd83dbSDimitry Andric 175ffd83dbSDimitry Andric namespace gwp_asan { 185ffd83dbSDimitry Andric 195ffd83dbSDimitry Andric const char *ErrorToString(const Error &E) { 205ffd83dbSDimitry Andric switch (E) { 215ffd83dbSDimitry Andric case Error::UNKNOWN: 225ffd83dbSDimitry Andric return "Unknown"; 235ffd83dbSDimitry Andric case Error::USE_AFTER_FREE: 245ffd83dbSDimitry Andric return "Use After Free"; 255ffd83dbSDimitry Andric case Error::DOUBLE_FREE: 265ffd83dbSDimitry Andric return "Double Free"; 275ffd83dbSDimitry Andric case Error::INVALID_FREE: 285ffd83dbSDimitry Andric return "Invalid (Wild) Free"; 295ffd83dbSDimitry Andric case Error::BUFFER_OVERFLOW: 305ffd83dbSDimitry Andric return "Buffer Overflow"; 315ffd83dbSDimitry Andric case Error::BUFFER_UNDERFLOW: 325ffd83dbSDimitry Andric return "Buffer Underflow"; 335ffd83dbSDimitry Andric } 345ffd83dbSDimitry Andric __builtin_trap(); 355ffd83dbSDimitry Andric } 365ffd83dbSDimitry Andric 37*e8d8bef9SDimitry Andric constexpr size_t AllocationMetadata::kStackFrameStorageBytes; 38*e8d8bef9SDimitry Andric constexpr size_t AllocationMetadata::kMaxTraceLengthToCollect; 39*e8d8bef9SDimitry Andric 405ffd83dbSDimitry Andric void AllocationMetadata::RecordAllocation(uintptr_t AllocAddr, 415ffd83dbSDimitry Andric size_t AllocSize) { 425ffd83dbSDimitry Andric Addr = AllocAddr; 435ffd83dbSDimitry Andric Size = AllocSize; 445ffd83dbSDimitry Andric IsDeallocated = false; 455ffd83dbSDimitry Andric 465ffd83dbSDimitry Andric AllocationTrace.ThreadID = getThreadID(); 475ffd83dbSDimitry Andric DeallocationTrace.TraceSize = 0; 485ffd83dbSDimitry Andric DeallocationTrace.ThreadID = kInvalidThreadID; 495ffd83dbSDimitry Andric } 505ffd83dbSDimitry Andric 515ffd83dbSDimitry Andric void AllocationMetadata::RecordDeallocation() { 525ffd83dbSDimitry Andric IsDeallocated = true; 535ffd83dbSDimitry Andric DeallocationTrace.ThreadID = getThreadID(); 545ffd83dbSDimitry Andric } 555ffd83dbSDimitry Andric 565ffd83dbSDimitry Andric void AllocationMetadata::CallSiteInfo::RecordBacktrace( 575ffd83dbSDimitry Andric options::Backtrace_t Backtrace) { 585ffd83dbSDimitry Andric TraceSize = 0; 595ffd83dbSDimitry Andric if (!Backtrace) 605ffd83dbSDimitry Andric return; 615ffd83dbSDimitry Andric 625ffd83dbSDimitry Andric uintptr_t UncompressedBuffer[kMaxTraceLengthToCollect]; 635ffd83dbSDimitry Andric size_t BacktraceLength = 645ffd83dbSDimitry Andric Backtrace(UncompressedBuffer, kMaxTraceLengthToCollect); 655ffd83dbSDimitry Andric // Backtrace() returns the number of available frames, which may be greater 665ffd83dbSDimitry Andric // than the number of frames in the buffer. In this case, we need to only pack 675ffd83dbSDimitry Andric // the number of frames that are in the buffer. 685ffd83dbSDimitry Andric if (BacktraceLength > kMaxTraceLengthToCollect) 695ffd83dbSDimitry Andric BacktraceLength = kMaxTraceLengthToCollect; 705ffd83dbSDimitry Andric TraceSize = 715ffd83dbSDimitry Andric compression::pack(UncompressedBuffer, BacktraceLength, CompressedTrace, 725ffd83dbSDimitry Andric AllocationMetadata::kStackFrameStorageBytes); 735ffd83dbSDimitry Andric } 745ffd83dbSDimitry Andric 755ffd83dbSDimitry Andric size_t AllocatorState::maximumAllocationSize() const { return PageSize; } 765ffd83dbSDimitry Andric 775ffd83dbSDimitry Andric uintptr_t AllocatorState::slotToAddr(size_t N) const { 785ffd83dbSDimitry Andric return GuardedPagePool + (PageSize * (1 + N)) + (maximumAllocationSize() * N); 795ffd83dbSDimitry Andric } 805ffd83dbSDimitry Andric 815ffd83dbSDimitry Andric bool AllocatorState::isGuardPage(uintptr_t Ptr) const { 825ffd83dbSDimitry Andric assert(pointerIsMine(reinterpret_cast<void *>(Ptr))); 835ffd83dbSDimitry Andric size_t PageOffsetFromPoolStart = (Ptr - GuardedPagePool) / PageSize; 845ffd83dbSDimitry Andric size_t PagesPerSlot = maximumAllocationSize() / PageSize; 855ffd83dbSDimitry Andric return (PageOffsetFromPoolStart % (PagesPerSlot + 1)) == 0; 865ffd83dbSDimitry Andric } 875ffd83dbSDimitry Andric 885ffd83dbSDimitry Andric static size_t addrToSlot(const AllocatorState *State, uintptr_t Ptr) { 895ffd83dbSDimitry Andric size_t ByteOffsetFromPoolStart = Ptr - State->GuardedPagePool; 905ffd83dbSDimitry Andric return ByteOffsetFromPoolStart / 915ffd83dbSDimitry Andric (State->maximumAllocationSize() + State->PageSize); 925ffd83dbSDimitry Andric } 935ffd83dbSDimitry Andric 945ffd83dbSDimitry Andric size_t AllocatorState::getNearestSlot(uintptr_t Ptr) const { 955ffd83dbSDimitry Andric if (Ptr <= GuardedPagePool + PageSize) 965ffd83dbSDimitry Andric return 0; 975ffd83dbSDimitry Andric if (Ptr > GuardedPagePoolEnd - PageSize) 985ffd83dbSDimitry Andric return MaxSimultaneousAllocations - 1; 995ffd83dbSDimitry Andric 1005ffd83dbSDimitry Andric if (!isGuardPage(Ptr)) 1015ffd83dbSDimitry Andric return addrToSlot(this, Ptr); 1025ffd83dbSDimitry Andric 1035ffd83dbSDimitry Andric if (Ptr % PageSize <= PageSize / 2) 1045ffd83dbSDimitry Andric return addrToSlot(this, Ptr - PageSize); // Round down. 1055ffd83dbSDimitry Andric return addrToSlot(this, Ptr + PageSize); // Round up. 1065ffd83dbSDimitry Andric } 1075ffd83dbSDimitry Andric 1085ffd83dbSDimitry Andric } // namespace gwp_asan 109