1 //===-- common.cpp ----------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "gwp_asan/common.h"
10 #include "gwp_asan/stack_trace_compressor.h"
14 using AllocationMetadata
= gwp_asan::AllocationMetadata
;
15 using Error
= gwp_asan::Error
;
19 const char *ErrorToString(const Error
&E
) {
23 case Error::USE_AFTER_FREE
:
24 return "Use After Free";
25 case Error::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";
37 constexpr size_t AllocationMetadata::kStackFrameStorageBytes
;
38 constexpr size_t AllocationMetadata::kMaxTraceLengthToCollect
;
40 void AllocationMetadata::RecordAllocation(uintptr_t AllocAddr
,
43 RequestedSize
= AllocSize
;
44 IsDeallocated
= false;
46 AllocationTrace
.ThreadID
= getThreadID();
47 DeallocationTrace
.TraceSize
= 0;
48 DeallocationTrace
.ThreadID
= kInvalidThreadID
;
51 void AllocationMetadata::RecordDeallocation() {
53 DeallocationTrace
.ThreadID
= getThreadID();
56 void AllocationMetadata::CallSiteInfo::RecordBacktrace(
57 options::Backtrace_t Backtrace
) {
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
;
71 compression::pack(UncompressedBuffer
, BacktraceLength
, CompressedTrace
,
72 AllocationMetadata::kStackFrameStorageBytes
);
75 size_t AllocatorState::maximumAllocationSize() const { return PageSize
; }
77 uintptr_t AllocatorState::slotToAddr(size_t N
) const {
78 return GuardedPagePool
+ (PageSize
* (1 + N
)) + (maximumAllocationSize() * N
);
81 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;
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
);
94 size_t AllocatorState::getNearestSlot(uintptr_t Ptr
) const {
95 if (Ptr
<= GuardedPagePool
+ PageSize
)
97 if (Ptr
> GuardedPagePoolEnd
- PageSize
)
98 return MaxSimultaneousAllocations
- 1;
100 if (!isGuardPage(Ptr
))
101 return addrToSlot(this, Ptr
);
103 if (Ptr
% PageSize
<= PageSize
/ 2)
104 return addrToSlot(this, Ptr
- PageSize
); // Round down.
105 return addrToSlot(this, Ptr
+ PageSize
); // Round up.
108 uintptr_t AllocatorState::internallyDetectedErrorFaultAddress() const {
109 return GuardedPagePoolEnd
- 0x10;
112 } // namespace gwp_asan