Summary: Fix up a slight bug with the crash handler API, where we say that we return the size of the collected trace (instead of the size of the trace that's returned) when the return buffer is too small, and the result is truncated. Also, as a result, patch up a small uninitialized memory bug. Reviewers: morehouse, eugenis Reviewed By: eugenis Subscribers: #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D84652
109 lines
3.5 KiB
C++
109 lines
3.5 KiB
C++
//===-- common.cpp ----------------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "gwp_asan/common.h"
|
|
#include "gwp_asan/stack_trace_compressor.h"
|
|
|
|
#include <assert.h>
|
|
|
|
using AllocationMetadata = gwp_asan::AllocationMetadata;
|
|
using Error = gwp_asan::Error;
|
|
|
|
namespace gwp_asan {
|
|
|
|
const char *ErrorToString(const Error &E) {
|
|
switch (E) {
|
|
case Error::UNKNOWN:
|
|
return "Unknown";
|
|
case Error::USE_AFTER_FREE:
|
|
return "Use After Free";
|
|
case Error::DOUBLE_FREE:
|
|
return "Double Free";
|
|
case Error::INVALID_FREE:
|
|
return "Invalid (Wild) Free";
|
|
case Error::BUFFER_OVERFLOW:
|
|
return "Buffer Overflow";
|
|
case Error::BUFFER_UNDERFLOW:
|
|
return "Buffer Underflow";
|
|
}
|
|
__builtin_trap();
|
|
}
|
|
|
|
constexpr size_t AllocationMetadata::kStackFrameStorageBytes;
|
|
constexpr size_t AllocationMetadata::kMaxTraceLengthToCollect;
|
|
|
|
void AllocationMetadata::RecordAllocation(uintptr_t AllocAddr,
|
|
size_t AllocSize) {
|
|
Addr = AllocAddr;
|
|
Size = AllocSize;
|
|
IsDeallocated = false;
|
|
|
|
AllocationTrace.ThreadID = getThreadID();
|
|
DeallocationTrace.TraceSize = 0;
|
|
DeallocationTrace.ThreadID = kInvalidThreadID;
|
|
}
|
|
|
|
void AllocationMetadata::RecordDeallocation() {
|
|
IsDeallocated = true;
|
|
DeallocationTrace.ThreadID = getThreadID();
|
|
}
|
|
|
|
void AllocationMetadata::CallSiteInfo::RecordBacktrace(
|
|
options::Backtrace_t Backtrace) {
|
|
TraceSize = 0;
|
|
if (!Backtrace)
|
|
return;
|
|
|
|
uintptr_t UncompressedBuffer[kMaxTraceLengthToCollect];
|
|
size_t BacktraceLength =
|
|
Backtrace(UncompressedBuffer, kMaxTraceLengthToCollect);
|
|
// Backtrace() returns the number of available frames, which may be greater
|
|
// than the number of frames in the buffer. In this case, we need to only pack
|
|
// the number of frames that are in the buffer.
|
|
if (BacktraceLength > kMaxTraceLengthToCollect)
|
|
BacktraceLength = kMaxTraceLengthToCollect;
|
|
TraceSize =
|
|
compression::pack(UncompressedBuffer, BacktraceLength, CompressedTrace,
|
|
AllocationMetadata::kStackFrameStorageBytes);
|
|
}
|
|
|
|
size_t AllocatorState::maximumAllocationSize() const { return PageSize; }
|
|
|
|
uintptr_t AllocatorState::slotToAddr(size_t N) const {
|
|
return GuardedPagePool + (PageSize * (1 + N)) + (maximumAllocationSize() * N);
|
|
}
|
|
|
|
bool AllocatorState::isGuardPage(uintptr_t Ptr) const {
|
|
assert(pointerIsMine(reinterpret_cast<void *>(Ptr)));
|
|
size_t PageOffsetFromPoolStart = (Ptr - GuardedPagePool) / PageSize;
|
|
size_t PagesPerSlot = maximumAllocationSize() / PageSize;
|
|
return (PageOffsetFromPoolStart % (PagesPerSlot + 1)) == 0;
|
|
}
|
|
|
|
static size_t addrToSlot(const AllocatorState *State, uintptr_t Ptr) {
|
|
size_t ByteOffsetFromPoolStart = Ptr - State->GuardedPagePool;
|
|
return ByteOffsetFromPoolStart /
|
|
(State->maximumAllocationSize() + State->PageSize);
|
|
}
|
|
|
|
size_t AllocatorState::getNearestSlot(uintptr_t Ptr) const {
|
|
if (Ptr <= GuardedPagePool + PageSize)
|
|
return 0;
|
|
if (Ptr > GuardedPagePoolEnd - PageSize)
|
|
return MaxSimultaneousAllocations - 1;
|
|
|
|
if (!isGuardPage(Ptr))
|
|
return addrToSlot(this, Ptr);
|
|
|
|
if (Ptr % PageSize <= PageSize / 2)
|
|
return addrToSlot(this, Ptr - PageSize); // Round down.
|
|
return addrToSlot(this, Ptr + PageSize); // Round up.
|
|
}
|
|
|
|
} // namespace gwp_asan
|