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