• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2008 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_LIBARTBASE_BASE_MEM_MAP_H_
18  #define ART_LIBARTBASE_BASE_MEM_MAP_H_
19  
20  #include <stddef.h>
21  #include <sys/types.h>
22  
23  #include <map>
24  #include <mutex>
25  #include <string>
26  
27  #include "android-base/thread_annotations.h"
28  #include "macros.h"
29  
30  namespace art {
31  
32  #if defined(__LP64__) && !defined(__Fuchsia__) && \
33      (defined(__aarch64__) || defined(__riscv) || defined(__APPLE__))
34  #define USE_ART_LOW_4G_ALLOCATOR 1
35  #else
36  #if defined(__LP64__) && !defined(__Fuchsia__) && !defined(__x86_64__)
37  #error "Unrecognized 64-bit architecture."
38  #endif
39  #define USE_ART_LOW_4G_ALLOCATOR 0
40  #endif
41  
42  #ifdef __linux__
43  static constexpr bool kMadviseZeroes = true;
44  #define HAVE_MREMAP_SYSCALL true
45  #else
46  static constexpr bool kMadviseZeroes = false;
47  // We cannot ever perform MemMap::ReplaceWith on non-linux hosts since the syscall is not
48  // present.
49  #define HAVE_MREMAP_SYSCALL false
50  #endif
51  
52  // Used to keep track of mmap segments.
53  //
54  // On 64b systems not supporting MAP_32BIT, the implementation of MemMap will do a linear scan
55  // for free pages. For security, the start of this scan should be randomized. This requires a
56  // dynamic initializer.
57  // For this to work, it is paramount that there are no other static initializers that access MemMap.
58  // Otherwise, calls might see uninitialized values.
59  class MemMap {
60   public:
61    static constexpr bool kCanReplaceMapping = HAVE_MREMAP_SYSCALL;
62  
63    // Creates an invalid mapping.
MemMap()64    MemMap() {}
65  
66    // Creates an invalid mapping. Used when we want to be more explicit than MemMap().
Invalid()67    static MemMap Invalid() {
68      return MemMap();
69    }
70  
71    MemMap(MemMap&& other) noexcept REQUIRES(!MemMap::mem_maps_lock_);
72    MemMap& operator=(MemMap&& other) noexcept REQUIRES(!MemMap::mem_maps_lock_) {
73      Reset();
74      swap(other);
75      return *this;
76    }
77  
78    // Releases the memory mapping.
79    ~MemMap() REQUIRES(!MemMap::mem_maps_lock_);
80  
81    // Swap two MemMaps.
82    void swap(MemMap& other);
83  
Reset()84    void Reset() {
85      if (IsValid()) {
86        DoReset();
87      }
88    }
89  
IsValid()90    bool IsValid() const {
91      return base_size_ != 0u;
92    }
93  
94    // Replace the data in this memmmap with the data in the memmap pointed to by source. The caller
95    // relinquishes ownership of the source mmap.
96    //
97    // For the call to be successful:
98    //   * The range [dest->Begin, dest->Begin() + source->Size()] must not overlap with
99    //     [source->Begin(), source->End()].
100    //   * Neither source nor dest may be 'reused' mappings (they must own all the pages associated
101    //     with them.
102    //   * kCanReplaceMapping must be true.
103    //   * Neither source nor dest may use manual redzones.
104    //   * Both source and dest must have the same offset from the nearest page boundary.
105    //   * mremap must succeed when called on the mappings.
106    //
107    // If this call succeeds it will return true and:
108    //   * Invalidate *source
109    //   * The protection of this will remain the same.
110    //   * The size of this will be the size of the source
111    //   * The data in this will be the data from source.
112    //
113    // If this call fails it will return false and make no changes to *source or this. The ownership
114    // of the source mmap is returned to the caller.
115    bool ReplaceWith(/*in-out*/MemMap* source, /*out*/std::string* error);
116  
117    // Set a debug friendly name for a map. It will be prefixed with "dalvik-".
118    static void SetDebugName(void* map_ptr, const char* name, size_t size);
119  
120    // Request an anonymous region of length 'byte_count' and a requested base address.
121    // Use null as the requested base address if you don't care.
122    //
123    // `reuse` allows re-mapping an address range from an existing mapping which retains the
124    // ownership of the memory. Alternatively, `reservation` allows re-mapping the start of an
125    // existing reservation mapping, transferring the ownership of the memory to the new MemMap.
126    //
127    // The word "anonymous" in this context means "not backed by a file". The supplied
128    // 'name' will be used -- on systems that support it -- to give the mapping
129    // a name.
130    //
131    // On success, returns a valid MemMap. On failure, returns an invalid MemMap.
132    static MemMap MapAnonymous(const char* name,
133                               uint8_t* addr,
134                               size_t byte_count,
135                               int prot,
136                               bool low_4gb,
137                               bool reuse,
138                               /*inout*/MemMap* reservation,
139                               /*out*/std::string* error_msg,
140                               bool use_debug_name = true);
141  
142    // Request an aligned anonymous region. We can't directly ask for a MAP_SHARED (anonymous or
143    // otherwise) mapping to be aligned as in that case file offset is involved and could make
144    // the starting offset to be out of sync with another mapping of the same file.
145    static MemMap MapAnonymousAligned(const char* name,
146                                      size_t byte_count,
147                                      int prot,
148                                      bool low_4gb,
149                                      size_t alignment,
150                                      /*out=*/std::string* error_msg);
151  
MapAnonymous(const char * name,size_t byte_count,int prot,bool low_4gb,std::string * error_msg)152    static MemMap MapAnonymous(const char* name,
153                               size_t byte_count,
154                               int prot,
155                               bool low_4gb,
156                               /*out*/std::string* error_msg) {
157      return MapAnonymous(name,
158                          /*addr=*/ nullptr,
159                          byte_count,
160                          prot,
161                          low_4gb,
162                          /*reuse=*/ false,
163                          /*reservation=*/ nullptr,
164                          error_msg);
165    }
MapAnonymous(const char * name,size_t byte_count,int prot,bool low_4gb,MemMap * reservation,std::string * error_msg)166    static MemMap MapAnonymous(const char* name,
167                               size_t byte_count,
168                               int prot,
169                               bool low_4gb,
170                               MemMap* reservation,
171                               /*out*/std::string* error_msg) {
172      return MapAnonymous(name,
173                          /*addr=*/ (reservation != nullptr) ? reservation->Begin() : nullptr,
174                          byte_count,
175                          prot,
176                          low_4gb,
177                          /*reuse=*/ false,
178                          reservation,
179                          error_msg);
180    }
181  
182    // Create placeholder for a region allocated by direct call to mmap.
183    // This is useful when we do not have control over the code calling mmap,
184    // but when we still want to keep track of it in the list.
185    // The region is not considered to be owned and will not be unmmaped.
186    static MemMap MapPlaceholder(const char* name, uint8_t* addr, size_t byte_count);
187  
188    // Map part of a file, taking care of non-page aligned offsets. The
189    // "start" offset is absolute, not relative.
190    //
191    // On success, returns a valid MemMap. On failure, returns an invalid MemMap.
MapFile(size_t byte_count,int prot,int flags,int fd,off_t start,bool low_4gb,const char * filename,std::string * error_msg)192    static MemMap MapFile(size_t byte_count,
193                          int prot,
194                          int flags,
195                          int fd,
196                          off_t start,
197                          bool low_4gb,
198                          const char* filename,
199                          std::string* error_msg) {
200      return MapFileAtAddress(nullptr,
201                              byte_count,
202                              prot,
203                              flags,
204                              fd,
205                              start,
206                              /*low_4gb=*/ low_4gb,
207                              filename,
208                              /*reuse=*/ false,
209                              /*reservation=*/ nullptr,
210                              error_msg);
211    }
212  
213    // Map part of a file, taking care of non-page aligned offsets. The "start" offset is absolute,
214    // not relative. This version allows requesting a specific address for the base of the mapping.
215    //
216    // `reuse` allows re-mapping an address range from an existing mapping which retains the
217    // ownership of the memory. Alternatively, `reservation` allows re-mapping the start of an
218    // existing reservation mapping, transferring the ownership of the memory to the new MemMap.
219    //
220    // If error_msg is null then we do not print /proc/maps to the log if MapFileAtAddress fails.
221    // This helps improve performance of the fail case since reading and printing /proc/maps takes
222    // several milliseconds in the worst case.
223    //
224    // On success, returns a valid MemMap. On failure, returns an invalid MemMap.
225    static MemMap MapFileAtAddress(uint8_t* addr,
226                                   size_t byte_count,
227                                   int prot,
228                                   int flags,
229                                   int fd,
230                                   off_t start,
231                                   bool low_4gb,
232                                   const char* filename,
233                                   bool reuse,
234                                   /*inout*/MemMap* reservation,
235                                   /*out*/std::string* error_msg);
236  
GetName()237    const std::string& GetName() const {
238      return name_;
239    }
240  
241    bool Sync();
242  
243    bool Protect(int prot);
244  
245    void MadviseDontNeedAndZero();
246    int MadviseDontFork();
247  
GetProtect()248    int GetProtect() const {
249      return prot_;
250    }
251  
Begin()252    uint8_t* Begin() const {
253      return begin_;
254    }
255  
Size()256    size_t Size() const {
257      return size_;
258    }
259  
260    // Resize the mem-map by unmapping pages at the end. Currently only supports shrinking.
261    void SetSize(size_t new_size);
262  
End()263    uint8_t* End() const {
264      return Begin() + Size();
265    }
266  
BaseBegin()267    void* BaseBegin() const {
268      return base_begin_;
269    }
270  
BaseSize()271    size_t BaseSize() const {
272      return base_size_;
273    }
274  
BaseEnd()275    void* BaseEnd() const {
276      return reinterpret_cast<uint8_t*>(BaseBegin()) + BaseSize();
277    }
278  
HasAddress(const void * addr)279    bool HasAddress(const void* addr) const {
280      return Begin() <= addr && addr < End();
281    }
282  
283    // Unmap the pages at end and remap them to create another memory map.
284    MemMap RemapAtEnd(uint8_t* new_end,
285                      const char* tail_name,
286                      int tail_prot,
287                      std::string* error_msg,
288                      bool use_debug_name = true);
289  
290    // Unmap the pages of a file at end and remap them to create another memory map.
291    MemMap RemapAtEnd(uint8_t* new_end,
292                      const char* tail_name,
293                      int tail_prot,
294                      int tail_flags,
295                      int fd,
296                      off_t offset,
297                      std::string* error_msg,
298                      bool use_debug_name = true);
299  
300    // Take ownership of pages at the beginning of the mapping. The mapping must be an
301    // anonymous reservation mapping, owning entire pages. The `byte_count` must not
302    // exceed the size of this reservation.
303    //
304    // Returns a mapping owning `byte_count` bytes rounded up to entire pages
305    // with size set to the passed `byte_count`. If 'reuse' is true then the caller
306    // is responsible for unmapping the taken pages.
307    MemMap TakeReservedMemory(size_t byte_count, bool reuse = false);
308  
309    static bool CheckNoGaps(MemMap& begin_map, MemMap& end_map)
310        REQUIRES(!MemMap::mem_maps_lock_);
311    static void DumpMaps(std::ostream& os, bool terse = false)
312        REQUIRES(!MemMap::mem_maps_lock_);
313  
314    // Init and Shutdown are NOT thread safe.
315    // Both may be called multiple times and MemMap objects may be created any
316    // time after the first call to Init and before the first call to Shutodwn.
317    static void Init() REQUIRES(!MemMap::mem_maps_lock_);
318    static void Shutdown() REQUIRES(!MemMap::mem_maps_lock_);
319    static bool IsInitialized();
320  
321    // If the map is PROT_READ, try to read each page of the map to check it is in fact readable (not
322    // faulting). This is used to diagnose a bug b/19894268 where mprotect doesn't seem to be working
323    // intermittently.
324    void TryReadable();
325  
326    // Align the map by unmapping the unaligned part at the lower end and if 'align_both_ends' is
327    // true, then the higher end as well.
328    void AlignBy(size_t alignment, bool align_both_ends = true);
329  
330    // For annotation reasons.
GetMemMapsLock()331    static std::mutex* GetMemMapsLock() RETURN_CAPABILITY(mem_maps_lock_) {
332      return nullptr;
333    }
334  
335    // Reset in a forked process the MemMap whose memory has been madvised MADV_DONTFORK
336    // in the parent process.
337    void ResetInForkedProcess();
338  
339    // 'redzone_size_ == 0' indicates that we are not using memory-tool on this mapping.
GetRedzoneSize()340    size_t GetRedzoneSize() const { return redzone_size_; }
341  
342   private:
343    MemMap(const std::string& name,
344           uint8_t* begin,
345           size_t size,
346           void* base_begin,
347           size_t base_size,
348           int prot,
349           bool reuse,
350           size_t redzone_size = 0) REQUIRES(!MemMap::mem_maps_lock_);
351  
352    void DoReset();
353    void Invalidate();
354    void SwapMembers(MemMap& other);
355  
356    static void DumpMapsLocked(std::ostream& os, bool terse)
357        REQUIRES(MemMap::mem_maps_lock_);
358    static bool HasMemMap(MemMap& map)
359        REQUIRES(MemMap::mem_maps_lock_);
360    static MemMap* GetLargestMemMapAt(void* address)
361        REQUIRES(MemMap::mem_maps_lock_);
362    static bool ContainedWithinExistingMap(uint8_t* ptr, size_t size, std::string* error_msg)
363        REQUIRES(!MemMap::mem_maps_lock_);
364  
365    // Internal version of mmap that supports low 4gb emulation.
366    static void* MapInternal(void* addr,
367                             size_t length,
368                             int prot,
369                             int flags,
370                             int fd,
371                             off_t offset,
372                             bool low_4gb)
373        REQUIRES(!MemMap::mem_maps_lock_);
374    static void* MapInternalArtLow4GBAllocator(size_t length,
375                                               int prot,
376                                               int flags,
377                                               int fd,
378                                               off_t offset)
379        REQUIRES(!MemMap::mem_maps_lock_);
380  
381    // Release memory owned by a reservation mapping.
382    void ReleaseReservedMemory(size_t byte_count);
383  
384    // member function to access real_munmap
385    static bool CheckMapRequest(uint8_t* expected_ptr,
386                                void* actual_ptr,
387                                size_t byte_count,
388                                std::string* error_msg);
389  
390    static bool CheckReservation(uint8_t* expected_ptr,
391                                 size_t byte_count,
392                                 const char* name,
393                                 const MemMap& reservation,
394                                 /*out*/std::string* error_msg);
395  
396    std::string name_;
397    uint8_t* begin_ = nullptr;    // Start of data. May be changed by AlignBy.
398    size_t size_ = 0u;            // Length of data.
399  
400    void* base_begin_ = nullptr;  // Page-aligned base address. May be changed by AlignBy.
401    size_t base_size_ = 0u;       // Length of mapping. May be changed by RemapAtEnd (ie Zygote).
402    int prot_ = 0;                // Protection of the map.
403  
404    // When reuse_ is true, this is just a view of an existing mapping
405    // and we do not take ownership and are not responsible for
406    // unmapping.
407    bool reuse_ = false;
408  
409    // When already_unmapped_ is true the destructor will not call munmap.
410    bool already_unmapped_ = false;
411  
412    size_t redzone_size_ = 0u;
413  
414  #if USE_ART_LOW_4G_ALLOCATOR
415    static uintptr_t next_mem_pos_;   // Next memory location to check for low_4g extent.
416  
417    static void* TryMemMapLow4GB(void* ptr,
418                                 size_t page_aligned_byte_count,
419                                 int prot,
420                                 int flags,
421                                 int fd,
422                                 off_t offset);
423  #endif
424  
425    static void TargetMMapInit();
426    static void* TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off);
427    static int TargetMUnmap(void* start, size_t len);
428  
429    static std::mutex* mem_maps_lock_;
430  
431    friend class MemMapTest;  // To allow access to base_begin_ and base_size_.
432  };
433  
swap(MemMap & lhs,MemMap & rhs)434  inline void swap(MemMap& lhs, MemMap& rhs) {
435    lhs.swap(rhs);
436  }
437  
438  std::ostream& operator<<(std::ostream& os, const MemMap& mem_map);
439  
440  // Zero and release pages if possible, no requirements on alignments.
441  void ZeroAndReleasePages(void* address, size_t length);
442  
443  }  // namespace art
444  
445  #endif  // ART_LIBARTBASE_BASE_MEM_MAP_H_
446