1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_INL_H_
18 #define ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_INL_H_
19
20 #include "base/memory_tool.h"
21 #include "memory_tool_malloc_space.h"
22 #include "memory_tool_settings.h"
23
24 namespace art {
25 namespace gc {
26 namespace space {
27
28 namespace memory_tool_details {
29
30 template <size_t kMemoryToolRedZoneBytes, bool kUseObjSizeForUsable>
AdjustForValgrind(void * obj_with_rdz,size_t num_bytes,size_t bytes_allocated,size_t usable_size,size_t bytes_tl_bulk_allocated,size_t * bytes_allocated_out,size_t * usable_size_out,size_t * bytes_tl_bulk_allocated_out)31 inline mirror::Object* AdjustForValgrind(void* obj_with_rdz, size_t num_bytes,
32 size_t bytes_allocated, size_t usable_size,
33 size_t bytes_tl_bulk_allocated,
34 size_t* bytes_allocated_out, size_t* usable_size_out,
35 size_t* bytes_tl_bulk_allocated_out) {
36 if (bytes_allocated_out != nullptr) {
37 *bytes_allocated_out = bytes_allocated;
38 }
39 if (bytes_tl_bulk_allocated_out != nullptr) {
40 *bytes_tl_bulk_allocated_out = bytes_tl_bulk_allocated;
41 }
42
43 // This cuts over-provision and is a trade-off between testing the over-provisioning code paths
44 // vs checking overflows in the regular paths.
45 if (usable_size_out != nullptr) {
46 if (kUseObjSizeForUsable) {
47 *usable_size_out = num_bytes;
48 } else {
49 *usable_size_out = usable_size - 2 * kMemoryToolRedZoneBytes;
50 }
51 }
52
53 // Left redzone.
54 MEMORY_TOOL_MAKE_NOACCESS(obj_with_rdz, kMemoryToolRedZoneBytes);
55
56 // Make requested memory readable.
57 // (If the allocator assumes memory is zeroed out, we might get UNDEFINED warnings, so make
58 // everything DEFINED initially.)
59 mirror::Object* result = reinterpret_cast<mirror::Object*>(
60 reinterpret_cast<uint8_t*>(obj_with_rdz) + kMemoryToolRedZoneBytes);
61 MEMORY_TOOL_MAKE_DEFINED(result, num_bytes);
62
63 // Right redzone. Assumes that if bytes_allocated > usable_size, then the difference is
64 // management data at the upper end, and for simplicity we will not protect that.
65 // At the moment, this fits RosAlloc (no management data in a slot, usable_size == alloc_size)
66 // and DlMalloc (allocation_size = (usable_size == num_bytes) + 4, 4 is management)
67 MEMORY_TOOL_MAKE_NOACCESS(reinterpret_cast<uint8_t*>(result) + num_bytes,
68 usable_size - (num_bytes + kMemoryToolRedZoneBytes));
69
70 return result;
71 }
72
GetObjSizeNoThreadSafety(mirror::Object * obj)73 inline size_t GetObjSizeNoThreadSafety(mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS {
74 return obj->SizeOf<kVerifyNone>();
75 }
76
77 } // namespace memory_tool_details
78
79 template <typename S,
80 size_t kMemoryToolRedZoneBytes,
81 bool kAdjustForRedzoneInAllocSize,
82 bool kUseObjSizeForUsable>
83 mirror::Object*
84 MemoryToolMallocSpace<S,
85 kMemoryToolRedZoneBytes,
86 kAdjustForRedzoneInAllocSize,
AllocWithGrowth(Thread * self,size_t num_bytes,size_t * bytes_allocated_out,size_t * usable_size_out,size_t * bytes_tl_bulk_allocated_out)87 kUseObjSizeForUsable>::AllocWithGrowth(
88 Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out,
89 size_t* bytes_tl_bulk_allocated_out) {
90 size_t bytes_allocated;
91 size_t usable_size;
92 size_t bytes_tl_bulk_allocated;
93 void* obj_with_rdz = S::AllocWithGrowth(self, num_bytes + 2 * kMemoryToolRedZoneBytes,
94 &bytes_allocated, &usable_size,
95 &bytes_tl_bulk_allocated);
96 if (obj_with_rdz == nullptr) {
97 return nullptr;
98 }
99
100 return memory_tool_details::AdjustForValgrind<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
101 obj_with_rdz, num_bytes,
102 bytes_allocated, usable_size,
103 bytes_tl_bulk_allocated,
104 bytes_allocated_out,
105 usable_size_out,
106 bytes_tl_bulk_allocated_out);
107 }
108
109 template <typename S,
110 size_t kMemoryToolRedZoneBytes,
111 bool kAdjustForRedzoneInAllocSize,
112 bool kUseObjSizeForUsable>
113 mirror::Object* MemoryToolMallocSpace<S,
114 kMemoryToolRedZoneBytes,
115 kAdjustForRedzoneInAllocSize,
Alloc(Thread * self,size_t num_bytes,size_t * bytes_allocated_out,size_t * usable_size_out,size_t * bytes_tl_bulk_allocated_out)116 kUseObjSizeForUsable>::Alloc(
117 Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out,
118 size_t* bytes_tl_bulk_allocated_out) {
119 size_t bytes_allocated;
120 size_t usable_size;
121 size_t bytes_tl_bulk_allocated;
122 void* obj_with_rdz = S::Alloc(self, num_bytes + 2 * kMemoryToolRedZoneBytes,
123 &bytes_allocated, &usable_size, &bytes_tl_bulk_allocated);
124 if (obj_with_rdz == nullptr) {
125 return nullptr;
126 }
127
128 return memory_tool_details::AdjustForValgrind<kMemoryToolRedZoneBytes,
129 kUseObjSizeForUsable>(obj_with_rdz, num_bytes,
130 bytes_allocated, usable_size,
131 bytes_tl_bulk_allocated,
132 bytes_allocated_out,
133 usable_size_out,
134 bytes_tl_bulk_allocated_out);
135 }
136
137 template <typename S,
138 size_t kMemoryToolRedZoneBytes,
139 bool kAdjustForRedzoneInAllocSize,
140 bool kUseObjSizeForUsable>
141 mirror::Object* MemoryToolMallocSpace<S,
142 kMemoryToolRedZoneBytes,
143 kAdjustForRedzoneInAllocSize,
AllocThreadUnsafe(Thread * self,size_t num_bytes,size_t * bytes_allocated_out,size_t * usable_size_out,size_t * bytes_tl_bulk_allocated_out)144 kUseObjSizeForUsable>::AllocThreadUnsafe(
145 Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out,
146 size_t* bytes_tl_bulk_allocated_out) {
147 size_t bytes_allocated;
148 size_t usable_size;
149 size_t bytes_tl_bulk_allocated;
150 void* obj_with_rdz = S::AllocThreadUnsafe(self, num_bytes + 2 * kMemoryToolRedZoneBytes,
151 &bytes_allocated, &usable_size,
152 &bytes_tl_bulk_allocated);
153 if (obj_with_rdz == nullptr) {
154 return nullptr;
155 }
156
157 return memory_tool_details::AdjustForValgrind<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
158 obj_with_rdz, num_bytes,
159 bytes_allocated, usable_size,
160 bytes_tl_bulk_allocated,
161 bytes_allocated_out,
162 usable_size_out,
163 bytes_tl_bulk_allocated_out);
164 }
165
166 template <typename S,
167 size_t kMemoryToolRedZoneBytes,
168 bool kAdjustForRedzoneInAllocSize,
169 bool kUseObjSizeForUsable>
170 size_t MemoryToolMallocSpace<S,
171 kMemoryToolRedZoneBytes,
172 kAdjustForRedzoneInAllocSize,
AllocationSize(mirror::Object * obj,size_t * usable_size)173 kUseObjSizeForUsable>::AllocationSize(
174 mirror::Object* obj, size_t* usable_size) {
175 size_t result = S::AllocationSize(reinterpret_cast<mirror::Object*>(
176 reinterpret_cast<uint8_t*>(obj) - (kAdjustForRedzoneInAllocSize ? kMemoryToolRedZoneBytes : 0)),
177 usable_size);
178 if (usable_size != nullptr) {
179 if (kUseObjSizeForUsable) {
180 *usable_size = memory_tool_details::GetObjSizeNoThreadSafety(obj);
181 } else {
182 *usable_size = *usable_size - 2 * kMemoryToolRedZoneBytes;
183 }
184 }
185 return result;
186 }
187
188 template <typename S,
189 size_t kMemoryToolRedZoneBytes,
190 bool kAdjustForRedzoneInAllocSize,
191 bool kUseObjSizeForUsable>
192 size_t MemoryToolMallocSpace<S,
193 kMemoryToolRedZoneBytes,
194 kAdjustForRedzoneInAllocSize,
Free(Thread * self,mirror::Object * ptr)195 kUseObjSizeForUsable>::Free(
196 Thread* self, mirror::Object* ptr) {
197 void* obj_after_rdz = reinterpret_cast<void*>(ptr);
198 uint8_t* obj_with_rdz = reinterpret_cast<uint8_t*>(obj_after_rdz) - kMemoryToolRedZoneBytes;
199
200 // Make redzones undefined.
201 size_t usable_size;
202 size_t allocation_size = AllocationSize(ptr, &usable_size);
203
204 // Unprotect the allocation.
205 // Use the obj-size-for-usable flag to determine whether usable_size is the more important one,
206 // e.g., whether there's data in the allocation_size (and usable_size can't be trusted).
207 if (kUseObjSizeForUsable) {
208 MEMORY_TOOL_MAKE_UNDEFINED(obj_with_rdz, allocation_size);
209 } else {
210 MEMORY_TOOL_MAKE_UNDEFINED(obj_with_rdz, usable_size + 2 * kMemoryToolRedZoneBytes);
211 }
212
213 return S::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
214 }
215
216 template <typename S,
217 size_t kMemoryToolRedZoneBytes,
218 bool kAdjustForRedzoneInAllocSize,
219 bool kUseObjSizeForUsable>
220 size_t MemoryToolMallocSpace<S,
221 kMemoryToolRedZoneBytes,
222 kAdjustForRedzoneInAllocSize,
FreeList(Thread * self,size_t num_ptrs,mirror::Object ** ptrs)223 kUseObjSizeForUsable>::FreeList(
224 Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
225 size_t freed = 0;
226 for (size_t i = 0; i < num_ptrs; i++) {
227 freed += Free(self, ptrs[i]);
228 ptrs[i] = nullptr;
229 }
230 return freed;
231 }
232
233 template <typename S,
234 size_t kMemoryToolRedZoneBytes,
235 bool kAdjustForRedzoneInAllocSize,
236 bool kUseObjSizeForUsable>
237 template <typename... Params>
238 MemoryToolMallocSpace<S,
239 kMemoryToolRedZoneBytes,
240 kAdjustForRedzoneInAllocSize,
MemoryToolMallocSpace(MemMap * mem_map,size_t initial_size,Params...params)241 kUseObjSizeForUsable>::MemoryToolMallocSpace(
242 MemMap* mem_map, size_t initial_size, Params... params) : S(mem_map, initial_size, params...) {
243 // Don't want to change the valgrind states of the mem map here as the allocator is already
244 // initialized at this point and that may interfere with what the allocator does internally. Note
245 // that the tail beyond the initial size is mprotected.
246 }
247
248 template <typename S,
249 size_t kMemoryToolRedZoneBytes,
250 bool kAdjustForRedzoneInAllocSize,
251 bool kUseObjSizeForUsable>
252 size_t MemoryToolMallocSpace<S,
253 kMemoryToolRedZoneBytes,
254 kAdjustForRedzoneInAllocSize,
MaxBytesBulkAllocatedFor(size_t num_bytes)255 kUseObjSizeForUsable>::MaxBytesBulkAllocatedFor(size_t num_bytes) {
256 return S::MaxBytesBulkAllocatedFor(num_bytes + 2 * kMemoryToolRedZoneBytes);
257 }
258
259 } // namespace space
260 } // namespace gc
261 } // namespace art
262
263 #endif // ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_INL_H_
264