1 //===-- mem_map_base.h ------------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef SCUDO_MEM_MAP_BASE_H_
10 #define SCUDO_MEM_MAP_BASE_H_
16 // In Scudo, every memory operation will be fulfilled through a
17 // platform-specific `MemMap` instance. The essential APIs are listed in the
18 // `MemMapBase` below. This is implemented in CRTP, so for each implementation,
19 // it has to implement all of the 'Impl' named functions.
20 template <class Derived
> class MemMapBase
{
22 constexpr MemMapBase() = default;
24 // This is used to map a new set of contiguous pages. Note that the `Addr` is
25 // only a suggestion to the system.
26 bool map(uptr Addr
, uptr Size
, const char *Name
, uptr Flags
= 0) {
27 DCHECK(!isAllocated());
28 return invokeImpl(&Derived::mapImpl
, Addr
, Size
, Name
, Flags
);
31 // This is used to unmap partial/full pages from the beginning or the end.
32 // I.e., the result pages are expected to be still contiguous.
33 void unmap(uptr Addr
, uptr Size
) {
34 DCHECK(isAllocated());
35 DCHECK((Addr
== getBase()) || (Addr
+ Size
== getBase() + getCapacity()));
36 invokeImpl(&Derived::unmapImpl
, Addr
, Size
);
39 // This is used to remap a mapped range (either from map() or dispatched from
40 // ReservedMemory). For example, we have reserved several pages and then we
41 // want to remap them with different accessibility.
42 bool remap(uptr Addr
, uptr Size
, const char *Name
, uptr Flags
= 0) {
43 DCHECK(isAllocated());
44 DCHECK((Addr
>= getBase()) && (Addr
+ Size
<= getBase() + getCapacity()));
45 return invokeImpl(&Derived::remapImpl
, Addr
, Size
, Name
, Flags
);
48 // This is used to update the pages' access permission. For example, mark
49 // pages as no read/write permission.
50 void setMemoryPermission(uptr Addr
, uptr Size
, uptr Flags
) {
51 DCHECK(isAllocated());
52 DCHECK((Addr
>= getBase()) && (Addr
+ Size
<= getBase() + getCapacity()));
53 return invokeImpl(&Derived::setMemoryPermissionImpl
, Addr
, Size
, Flags
);
56 // Suggest releasing a set of contiguous physical pages back to the OS. Note
57 // that only physical pages are supposed to be released. Any release of
58 // virtual pages may lead to undefined behavior.
59 void releasePagesToOS(uptr From
, uptr Size
) {
60 DCHECK(isAllocated());
61 DCHECK((From
>= getBase()) && (From
+ Size
<= getBase() + getCapacity()));
62 invokeImpl(&Derived::releasePagesToOSImpl
, From
, Size
);
64 // This is similar to the above one except that any subsequent access to the
65 // released pages will return with zero-filled pages.
66 void releaseAndZeroPagesToOS(uptr From
, uptr Size
) {
67 DCHECK(isAllocated());
68 DCHECK((From
>= getBase()) && (From
+ Size
<= getBase() + getCapacity()));
69 invokeImpl(&Derived::releaseAndZeroPagesToOSImpl
, From
, Size
);
72 uptr
getBase() { return invokeImpl(&Derived::getBaseImpl
); }
73 uptr
getCapacity() { return invokeImpl(&Derived::getCapacityImpl
); }
75 bool isAllocated() { return getBase() != 0U; }
78 template <typename R
, typename
... Args
>
79 R
invokeImpl(R (Derived::*MemFn
)(Args
...), Args
... args
) {
80 return (static_cast<Derived
*>(this)->*MemFn
)(args
...);
84 // `ReservedMemory` is a special memory handle which can be viewed as a page
85 // allocator. `ReservedMemory` will reserve a contiguous pages and the later
86 // page request can be fulfilled at the designated address. This is used when
87 // we want to ensure the virtual address of the MemMap will be in a known range.
88 // This is implemented in CRTP, so for each
89 // implementation, it has to implement all of the 'Impl' named functions.
90 template <class Derived
, typename MemMapTy
> class ReservedMemory
{
92 using MemMapT
= MemMapTy
;
93 constexpr ReservedMemory() = default;
95 // Reserve a chunk of memory at a suggested address.
96 bool create(uptr Addr
, uptr Size
, const char *Name
, uptr Flags
= 0) {
98 return invokeImpl(&Derived::createImpl
, Addr
, Size
, Name
, Flags
);
101 // Release the entire reserved memory.
104 invokeImpl(&Derived::releaseImpl
);
107 // Dispatch a sub-range of reserved memory. Note that any fragmentation of
108 // the reserved pages is managed by each implementation.
109 MemMapT
dispatch(uptr Addr
, uptr Size
) {
111 DCHECK((Addr
>= getBase()) && (Addr
+ Size
<= getBase() + getCapacity()));
112 return invokeImpl(&Derived::dispatchImpl
, Addr
, Size
);
115 uptr
getBase() { return invokeImpl(&Derived::getBaseImpl
); }
116 uptr
getCapacity() { return invokeImpl(&Derived::getCapacityImpl
); }
118 bool isCreated() { return getBase() != 0U; }
121 template <typename R
, typename
... Args
>
122 R
invokeImpl(R (Derived::*MemFn
)(Args
...), Args
... args
) {
123 return (static_cast<Derived
*>(this)->*MemFn
)(args
...);
129 #endif // SCUDO_MEM_MAP_BASE_H_