1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 #include "forward_declarations.h"
5 
6 #ifdef FEATURE_RWX_MEMORY
7 #define WRITE_ACCESS_HOLDER_ARG                 , rh::util::WriteAccessHolder *pRWAccessHolder
8 #define WRITE_ACCESS_HOLDER_ARG_NULL_DEFAULT    , rh::util::WriteAccessHolder *pRWAccessHolder = NULL
9 #define PASS_WRITE_ACCESS_HOLDER_ARG            , pRWAccessHolder
10 #else // FEATURE_RWX_MEMORY
11 #define WRITE_ACCESS_HOLDER_ARG
12 #define WRITE_ACCESS_HOLDER_ARG_NULL_DEFAULT
13 #define PASS_WRITE_ACCESS_HOLDER_ARG
14 #endif // FEATURE_RWX_MEMORY
15 
16 class AllocHeap
17 {
18   public:
19     AllocHeap();
20 
21 #ifdef FEATURE_RWX_MEMORY
22     // If pAccessMgr is non-NULL, it will be used to manage R/W access to the memory allocated.
23     AllocHeap(UInt32 rwProtectType = PAGE_READWRITE,
24               UInt32 roProtectType = 0, // 0 indicates "same as rwProtectType"
25               rh::util::MemAccessMgr* pAccessMgr = NULL);
26 #endif // FEATURE_RWX_MEMORY
27 
28     bool Init();
29 
30     bool Init(UInt8 *    pbInitialMem,
31               UIntNative cbInitialMemCommit,
32               UIntNative cbInitialMemReserve,
33               bool       fShouldFreeInitialMem);
34 
35     ~AllocHeap();
36 
37     // If AllocHeap was created with a MemAccessMgr, pRWAccessHolder must be non-NULL.
38     // On return, the holder will permit R/W access to the allocated memory until it
39     // is destructed.
40     UInt8 * Alloc(UIntNative cbMem WRITE_ACCESS_HOLDER_ARG_NULL_DEFAULT);
41 
42     // If AllocHeap was created with a MemAccessMgr, pRWAccessHolder must be non-NULL.
43     // On return, the holder will permit R/W access to the allocated memory until it
44     // is destructed.
45     UInt8 * AllocAligned(UIntNative cbMem,
46                          UIntNative alignment
47                          WRITE_ACCESS_HOLDER_ARG_NULL_DEFAULT);
48 
49     // Returns true if this AllocHeap owns the memory range [pvMem, pvMem+cbMem)
50     bool Contains(void * pvMem,
51                   UIntNative cbMem);
52 
53 #ifdef FEATURE_RWX_MEMORY
54     // Used with previously-allocated memory for which RW access is needed again.
55     // Returns true on success. R/W access will be granted until the holder is
56     // destructed.
57     bool AcquireWriteAccess(void* pvMem,
58                             UIntNative cbMem,
59                             rh::util::WriteAccessHolder* pHolder);
60 #endif // FEATURE_RWX_MEMORY
61 
62   private:
63     // Allocation Helpers
64     UInt8* _Alloc(UIntNative cbMem, UIntNative alignment WRITE_ACCESS_HOLDER_ARG);
65     bool _AllocNewBlock(UIntNative cbMem);
66     UInt8* _AllocFromCurBlock(UIntNative cbMem, UIntNative alignment WRITE_ACCESS_HOLDER_ARG);
67     bool _CommitFromCurBlock(UIntNative cbMem);
68 
69     // Access protection helpers
70 #ifdef FEATURE_RWX_MEMORY
71     bool _AcquireWriteAccess(UInt8* pvMem, UIntNative cbMem, rh::util::WriteAccessHolder* pHolder);
72 #endif // FEATURE_RWX_MEMORY
73     bool _UpdateMemPtrs(UInt8* pNextFree, UInt8* pFreeCommitEnd, UInt8* pFreeReserveEnd);
74     bool _UpdateMemPtrs(UInt8* pNextFree, UInt8* pFreeCommitEnd);
75     bool _UpdateMemPtrs(UInt8* pNextFree);
_UseAccessManager()76     bool _UseAccessManager() { return m_rwProtectType != m_roProtectType; }
77 
78     static const UIntNative s_minBlockSize = OS_PAGE_SIZE;
79 
80     typedef rh::util::MemRange Block;
81     typedef DPTR(Block) PTR_Block;
82     struct BlockListElem : public Block
83     {
BlockListElemBlockListElem84         BlockListElem(Block const & block)
85             : Block(block)
86             {}
87 
BlockListElemBlockListElem88         BlockListElem(UInt8 * pbMem, UIntNative  cbMem)
89             : Block(pbMem, cbMem)
90             {}
91 
92         Block       m_block;
93         PTR_Block   m_pNext;
94     };
95 
96     typedef SList<BlockListElem>    BlockList;
97     BlockList                       m_blockList;
98 
99     UInt32                          m_rwProtectType; // READ/WRITE/EXECUTE/etc
100     UInt32                          m_roProtectType; // What to do with fully allocated and initialized pages.
101 
102 #ifdef FEATURE_RWX_MEMORY
103     rh::util::MemAccessMgr*         m_pAccessMgr;
104     rh::util::WriteAccessHolder     m_hCurPageRW;   // Used to hold RW access to the current allocation page
105                                                     // Passed as pHint to MemAccessMgr::AcquireWriteAccess.
106 #endif // FEATURE_RWX_MEMORY
107     UInt8 *                         m_pNextFree;
108     UInt8 *                         m_pFreeCommitEnd;
109     UInt8 *                         m_pFreeReserveEnd;
110 
111     UInt8 *                         m_pbInitialMem;
112     bool                            m_fShouldFreeInitialMem;
113 
114     Crst                            m_lock;
115 
116     INDEBUG(bool                    m_fIsInit;)
117 };
118 typedef DPTR(AllocHeap) PTR_AllocHeap;
119 
120 //-------------------------------------------------------------------------------------------------
121 void * __cdecl operator new(size_t n, AllocHeap * alloc);
122 void * __cdecl operator new[](size_t n, AllocHeap * alloc);
123 
124