Home | History | Annotate | Download | only in space
      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>
     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 
     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,
     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,
    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,
    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,
    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,
    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,
    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,
    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,
    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