1 // Copyright 2014 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_APPLE_SCOPED_MACH_VM_H_ 6 #define BASE_APPLE_SCOPED_MACH_VM_H_ 7 8 #include <mach/mach.h> 9 #include <stddef.h> 10 11 #include <algorithm> 12 #include <utility> 13 14 #include "base/base_export.h" 15 #include "base/check_op.h" 16 17 // Use ScopedMachVM to supervise ownership of pages in the current process 18 // through the Mach VM subsystem. Pages allocated with vm_allocate can be 19 // released when exiting a scope with ScopedMachVM. 20 // 21 // The Mach VM subsystem operates on a page-by-page basis, and a single VM 22 // allocation managed by a ScopedMachVM object may span multiple pages. As far 23 // as Mach is concerned, allocated pages may be deallocated individually. This 24 // is in contrast to higher-level allocators such as malloc, where the base 25 // address of an allocation implies the size of an allocated block. 26 // Consequently, it is not sufficient to just pass the base address of an 27 // allocation to ScopedMachVM, it also needs to know the size of the 28 // allocation. To avoid any confusion, both the base address and size must 29 // be page-aligned. 30 // 31 // When dealing with Mach VM, base addresses will naturally be page-aligned, 32 // but user-specified sizes may not be. If there's a concern that a size is 33 // not page-aligned, use the mach_vm_round_page macro to correct it. 34 // 35 // Example: 36 // 37 // vm_address_t address = 0; 38 // vm_size_t size = 12345; // This requested size is not page-aligned. 39 // kern_return_t kr = 40 // vm_allocate(mach_task_self(), &address, size, VM_FLAGS_ANYWHERE); 41 // if (kr != KERN_SUCCESS) { 42 // return false; 43 // } 44 // ScopedMachVM vm_owner(address, mach_vm_round_page(size)); 45 46 namespace base::apple { 47 48 class BASE_EXPORT ScopedMachVM { 49 public: 50 explicit ScopedMachVM(vm_address_t address = 0, vm_size_t size = 0) address_(address)51 : address_(address), size_(size) { 52 DCHECK_EQ(address % PAGE_SIZE, 0u); 53 DCHECK_EQ(size % PAGE_SIZE, 0u); 54 } 55 56 ScopedMachVM(const ScopedMachVM&) = delete; 57 ScopedMachVM& operator=(const ScopedMachVM&) = delete; 58 ~ScopedMachVM()59 ~ScopedMachVM() { 60 if (size_) { 61 vm_deallocate(mach_task_self(), address_, size_); 62 } 63 } 64 65 // Resets the scoper to manage a new memory region. Both |address| and |size| 66 // must be page-aligned. If the new region is a smaller subset of the 67 // existing region (i.e. the new and old regions overlap), the non- 68 // overlapping part of the old region is deallocated. 69 void reset(vm_address_t address = 0, vm_size_t size = 0); 70 71 // Like reset() but does not DCHECK that |address| and |size| are page- 72 // aligned. 73 void reset_unaligned(vm_address_t address, vm_size_t size); 74 address()75 vm_address_t address() const { 76 return address_; 77 } 78 size()79 vm_size_t size() const { 80 return size_; 81 } 82 swap(ScopedMachVM & that)83 void swap(ScopedMachVM& that) { 84 std::swap(address_, that.address_); 85 std::swap(size_, that.size_); 86 } 87 release()88 void release() { 89 address_ = 0; 90 size_ = 0; 91 } 92 93 private: 94 vm_address_t address_; 95 vm_size_t size_; 96 }; 97 98 } // namespace base::apple 99 100 #endif // BASE_APPLE_SCOPED_MACH_VM_H_ 101