Bug Summary

File:projects/compiler-rt/lib/scudo/scudo_allocator_secondary.h
Warning:line 112, column 11
Value stored to 'ReservedBeg' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name scudo_malloc.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mthread-model posix -mframe-pointer=all -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-10~svn371925/build-llvm/projects/compiler-rt/lib/scudo -I /build/llvm-toolchain-snapshot-10~svn371925/projects/compiler-rt/lib/scudo -I /build/llvm-toolchain-snapshot-10~svn371925/build-llvm/include -I /build/llvm-toolchain-snapshot-10~svn371925/include -I /build/llvm-toolchain-snapshot-10~svn371925/projects/compiler-rt/lib/scudo/.. -U NDEBUG -D GWP_ASAN_HOOKS -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -Wno-unused-parameter -Wno-variadic-macros -Wno-non-virtual-dtor -std=c++14 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-10~svn371925/build-llvm/projects/compiler-rt/lib/scudo -fdebug-prefix-map=/build/llvm-toolchain-snapshot-10~svn371925=. -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -fvisibility-inlines-hidden -fno-rtti -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -o /tmp/scan-build-2019-09-15-043714-16238-1 -x c++ /build/llvm-toolchain-snapshot-10~svn371925/projects/compiler-rt/lib/scudo/scudo_malloc.cpp
1//===-- scudo_allocator_secondary.h -----------------------------*- 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/// Scudo Secondary Allocator.
10/// This services allocation that are too large to be serviced by the Primary
11/// Allocator. It is directly backed by the memory mapping functions of the
12/// operating system.
13///
14//===----------------------------------------------------------------------===//
15
16#ifndef SCUDO_ALLOCATOR_SECONDARY_H_
17#define SCUDO_ALLOCATOR_SECONDARY_H_
18
19#ifndef SCUDO_ALLOCATOR_H_
20# error "This file must be included inside scudo_allocator.h."
21#endif
22
23// Secondary backed allocations are standalone chunks that contain extra
24// information stored in a LargeChunk::Header prior to the frontend's header.
25//
26// The secondary takes care of alignment requirements (so that it can release
27// unnecessary pages in the rare event of larger alignments), and as such must
28// know about the frontend's header size.
29//
30// Since Windows doesn't support partial releasing of a reserved memory region,
31// we have to keep track of both the reserved and the committed memory.
32//
33// The resulting chunk resembles the following:
34//
35// +--------------------+
36// | Guard page(s) |
37// +--------------------+
38// | Unused space* |
39// +--------------------+
40// | LargeChunk::Header |
41// +--------------------+
42// | {Unp,P}ackedHeader |
43// +--------------------+
44// | Data (aligned) |
45// +--------------------+
46// | Unused space** |
47// +--------------------+
48// | Guard page(s) |
49// +--------------------+
50
51namespace LargeChunk {
52struct Header {
53 ReservedAddressRange StoredRange;
54 uptr CommittedSize;
55 uptr Size;
56};
57constexpr uptr getHeaderSize() {
58 return RoundUpTo(sizeof(Header), MinAlignment);
59}
60static Header *getHeader(uptr Ptr) {
61 return reinterpret_cast<Header *>(Ptr - getHeaderSize());
62}
63static Header *getHeader(const void *Ptr) {
64 return getHeader(reinterpret_cast<uptr>(Ptr));
65}
66} // namespace LargeChunk
67
68class LargeMmapAllocator {
69 public:
70 void Init() {
71 internal_memset(this, 0, sizeof(*this));
72 }
73
74 void *Allocate(AllocatorStats *Stats, uptr Size, uptr Alignment) {
75 const uptr UserSize = Size - Chunk::getHeaderSize();
76 // The Scudo frontend prevents us from allocating more than
77 // MaxAllowedMallocSize, so integer overflow checks would be superfluous.
78 uptr ReservedSize = Size + LargeChunk::getHeaderSize();
79 if (UNLIKELY(Alignment > MinAlignment)__builtin_expect(!!(Alignment > MinAlignment), 0))
80 ReservedSize += Alignment;
81 const uptr PageSize = GetPageSizeCached();
82 ReservedSize = RoundUpTo(ReservedSize, PageSize);
83 // Account for 2 guard pages, one before and one after the chunk.
84 ReservedSize += 2 * PageSize;
85
86 ReservedAddressRange AddressRange;
87 uptr ReservedBeg = AddressRange.Init(ReservedSize, SecondaryAllocatorName);
88 if (UNLIKELY(ReservedBeg == ~static_cast<uptr>(0))__builtin_expect(!!(ReservedBeg == ~static_cast<uptr>(0
)), 0)
)
89 return nullptr;
90 // A page-aligned pointer is assumed after that, so check it now.
91 DCHECK(IsAligned(ReservedBeg, PageSize));
92 uptr ReservedEnd = ReservedBeg + ReservedSize;
93 // The beginning of the user area for that allocation comes after the
94 // initial guard page, and both headers. This is the pointer that has to
95 // abide by alignment requirements.
96 uptr CommittedBeg = ReservedBeg + PageSize;
97 uptr UserBeg = CommittedBeg + HeadersSize;
98 uptr UserEnd = UserBeg + UserSize;
99 uptr CommittedEnd = RoundUpTo(UserEnd, PageSize);
100
101 // In the rare event of larger alignments, we will attempt to fit the mmap
102 // area better and unmap extraneous memory. This will also ensure that the
103 // offset and unused bytes field of the header stay small.
104 if (UNLIKELY(Alignment > MinAlignment)__builtin_expect(!!(Alignment > MinAlignment), 0)) {
105 if (!IsAligned(UserBeg, Alignment)) {
106 UserBeg = RoundUpTo(UserBeg, Alignment);
107 CommittedBeg = RoundDownTo(UserBeg - HeadersSize, PageSize);
108 const uptr NewReservedBeg = CommittedBeg - PageSize;
109 DCHECK_GE(NewReservedBeg, ReservedBeg);
110 if (!SANITIZER_WINDOWS0 && NewReservedBeg != ReservedBeg) {
111 AddressRange.Unmap(ReservedBeg, NewReservedBeg - ReservedBeg);
112 ReservedBeg = NewReservedBeg;
Value stored to 'ReservedBeg' is never read
113 }
114 UserEnd = UserBeg + UserSize;
115 CommittedEnd = RoundUpTo(UserEnd, PageSize);
116 }
117 const uptr NewReservedEnd = CommittedEnd + PageSize;
118 DCHECK_LE(NewReservedEnd, ReservedEnd);
119 if (!SANITIZER_WINDOWS0 && NewReservedEnd != ReservedEnd) {
120 AddressRange.Unmap(NewReservedEnd, ReservedEnd - NewReservedEnd);
121 ReservedEnd = NewReservedEnd;
122 }
123 }
124
125 DCHECK_LE(UserEnd, CommittedEnd);
126 const uptr CommittedSize = CommittedEnd - CommittedBeg;
127 // Actually mmap the memory, preserving the guard pages on either sides.
128 CHECK_EQ(CommittedBeg, AddressRange.Map(CommittedBeg, CommittedSize))do { __sanitizer::u64 v1 = (__sanitizer::u64)((CommittedBeg))
; __sanitizer::u64 v2 = (__sanitizer::u64)((AddressRange.Map(
CommittedBeg, CommittedSize))); if (__builtin_expect(!!(!(v1 ==
v2)), 0)) __sanitizer::CheckFailed("/build/llvm-toolchain-snapshot-10~svn371925/projects/compiler-rt/lib/scudo/scudo_allocator_secondary.h"
, 128, "(" "(CommittedBeg)" ") " "==" " (" "(AddressRange.Map(CommittedBeg, CommittedSize))"
")", v1, v2); } while (false)
;
129 const uptr Ptr = UserBeg - Chunk::getHeaderSize();
130 LargeChunk::Header *H = LargeChunk::getHeader(Ptr);
131 H->StoredRange = AddressRange;
132 H->Size = CommittedEnd - Ptr;
133 H->CommittedSize = CommittedSize;
134
135 // The primary adds the whole class size to the stats when allocating a
136 // chunk, so we will do something similar here. But we will not account for
137 // the guard pages.
138 {
139 SpinMutexLock l(&StatsMutex);
140 Stats->Add(AllocatorStatAllocated, CommittedSize);
141 Stats->Add(AllocatorStatMapped, CommittedSize);
142 AllocatedBytes += CommittedSize;
143 if (LargestSize < CommittedSize)
144 LargestSize = CommittedSize;
145 NumberOfAllocs++;
146 }
147
148 return reinterpret_cast<void *>(Ptr);
149 }
150
151 void Deallocate(AllocatorStats *Stats, void *Ptr) {
152 LargeChunk::Header *H = LargeChunk::getHeader(Ptr);
153 // Since we're unmapping the entirety of where the ReservedAddressRange
154 // actually is, copy onto the stack.
155 ReservedAddressRange AddressRange = H->StoredRange;
156 const uptr Size = H->CommittedSize;
157 {
158 SpinMutexLock l(&StatsMutex);
159 Stats->Sub(AllocatorStatAllocated, Size);
160 Stats->Sub(AllocatorStatMapped, Size);
161 FreedBytes += Size;
162 NumberOfFrees++;
163 }
164 AddressRange.Unmap(reinterpret_cast<uptr>(AddressRange.base()),
165 AddressRange.size());
166 }
167
168 static uptr GetActuallyAllocatedSize(void *Ptr) {
169 return LargeChunk::getHeader(Ptr)->Size;
170 }
171
172 void PrintStats() {
173 Printf("Stats: LargeMmapAllocator: allocated %zd times (%zd K), "
174 "freed %zd times (%zd K), remains %zd (%zd K) max %zd M\n",
175 NumberOfAllocs, AllocatedBytes >> 10, NumberOfFrees,
176 FreedBytes >> 10, NumberOfAllocs - NumberOfFrees,
177 (AllocatedBytes - FreedBytes) >> 10, LargestSize >> 20);
178 }
179
180 private:
181 static constexpr uptr HeadersSize =
182 LargeChunk::getHeaderSize() + Chunk::getHeaderSize();
183
184 StaticSpinMutex StatsMutex;
185 u32 NumberOfAllocs;
186 u32 NumberOfFrees;
187 uptr AllocatedBytes;
188 uptr FreedBytes;
189 uptr LargestSize;
190};
191
192#endif // SCUDO_ALLOCATOR_SECONDARY_H_