xref: /aosp_15_r20/external/cronet/base/apple/scoped_mach_vm.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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