source: trunk/Utilities/VirtualHeapPtr/VirtualHeapPtr.h @ 37

Last change on this file since 37 was 37, checked in by roman, 12 years ago
  • Property svn:keywords set to Id
File size: 9.3 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2011
3// Created by Roman Ryltsov roman@alax.info
4//
5// $Id: VirtualHeapPtr.h 37 2011-11-07 10:00:04Z roman $
6
7#pragma once
8
9////////////////////////////////////////////////////////////
10// CGlobalVirtualAllocator
11
12class CGlobalVirtualAllocator
13{
14private:
15        SIZE_T m_nPageSize;
16
17public:
18// CGlobalVirtualAllocator
19        CGlobalVirtualAllocator() throw() :
20                m_nPageSize(4 << 10) // 4L
21        {
22                SYSTEM_INFO Information;
23                GetSystemInfo(&Information);
24                m_nPageSize = Information.dwPageSize;
25                ATLASSERT(m_nPageSize);
26                ATLASSERT(!(m_nPageSize & (m_nPageSize - 1)));
27        }
28        SIZE_T GetPageSize() const throw()
29        {
30                return m_nPageSize;
31        }
32        SIZE_T Align(SIZE_T nDataSize) throw()
33        {
34                const SIZE_T nPageSize = GetPageSize();
35                ATLASSERT(nPageSize);
36                ATLASSERT(!(nPageSize & (nPageSize - 1)));
37                return (nDataSize + nPageSize - 1) & ~(nPageSize - 1);
38        }
39        static SIZE_T StaticAlign(SIZE_T nDataSize) throw();
40};
41
42__declspec(selectany) CGlobalVirtualAllocator g_GlobalVirtualAllocator;
43
44inline SIZE_T CGlobalVirtualAllocator::StaticAlign(SIZE_T nDataSize) throw()
45{
46        return g_GlobalVirtualAllocator.Align(nDataSize);
47}
48
49////////////////////////////////////////////////////////////
50// CVirtualAllocator
51
52class CVirtualAllocator
53{
54public:
55// CVirtualAllocator
56        static VOID* Allocate(_In_ SIZE_T nDataSize)
57        {
58                if(!nDataSize)
59                        return NULL;
60                VOID* pvData = VirtualAlloc(NULL, CGlobalVirtualAllocator::StaticAlign(nDataSize), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
61                ATLENSURE_THROW(pvData, AtlHresultFromLastError());
62                return pvData;
63        }
64        static VOID* Reallocate(_In_opt_ VOID* pvData, _In_ SIZE_T nDataSize)
65        {
66                MEMORY_BASIC_INFORMATION DataInformation;
67                if(pvData)
68                {
69                        ATLVERIFY(VirtualQuery(pvData, &DataInformation, sizeof DataInformation));
70                        if(nDataSize <= DataInformation.RegionSize)
71                                return pvData;
72                }
73                VOID* pvNewData = NULL;
74                if(nDataSize)
75                {
76                        pvNewData = VirtualAlloc(NULL, CGlobalVirtualAllocator::StaticAlign(nDataSize), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
77                        ATLENSURE_THROW(pvNewData, AtlHresultFromLastError());
78                        _ATLTRY
79                        {
80                                if(pvNewData && pvData)
81                                {
82                                        ATLASSERT(DataInformation.AllocationProtect == PAGE_READWRITE);
83                                        SIZE_T nCopyDataSize = nDataSize;
84                                        if(nCopyDataSize > DataInformation.RegionSize)
85                                                nCopyDataSize = DataInformation.RegionSize;
86                                        Checked::memcpy_s(pvNewData, nDataSize, pvData, nCopyDataSize);
87                                }
88                        }
89                        _ATLCATCHALL()
90                        {
91                                Free(pvData);
92                                _ATLRETHROW;
93                        }
94                }
95                if(pvData)
96                        Free(pvData);
97                return pvNewData;
98        }
99        static VOID Free(_In_opt_ VOID* pvData) throw()
100        {
101                if(!pvData)
102                        return;
103                ATLVERIFY(VirtualFree(pvData, 0, MEM_RELEASE));
104        }
105};
106
107////////////////////////////////////////////////////////////
108// CVirtualHeapPtr
109
110template <typename T>
111class CVirtualHeapPtr :
112        public CHeapPtr<T, CVirtualAllocator>
113{
114public:
115// CVirtualHeapPtr
116        CVirtualHeapPtr() throw()
117        {
118        }
119        explicit CVirtualHeapPtr(_In_ T* pData) throw() :
120                CHeapPtr<T, CVirtualAllocator>(pData)
121        {
122        }
123        VOID SetProtection(DWORD nProtection)
124        {
125                if(!m_pData)
126                        return;
127                MEMORY_BASIC_INFORMATION DataInformation;
128                ATLENSURE_THROW(VirtualQuery(m_pData, &DataInformation, sizeof DataInformation), AtlHresultFromLastError());
129                DWORD nCurrentProtection;
130                ATLENSURE_THROW(VirtualProtect(m_pData, DataInformation.RegionSize, nProtection, &nCurrentProtection), AtlHresultFromLastError());
131        }
132};
133
134////////////////////////////////////////////////////////////
135// CDebugAllocatorTraits
136
137class CDebugAllocatorTraits
138{
139public:
140// CDebugAllocatorTraits
141        static SIZE_T GetHeadSanityPageCount() throw()
142        {
143                return 1;
144        }
145        static SIZE_T GetTailSanityPageCount() throw()
146        {
147                return 1;
148        }
149        static BOOL IsHeadPadding() throw()
150        {
151                return TRUE;
152        }
153};
154
155////////////////////////////////////////////////////////////
156// CDebugAllocatorT, CDebugAllocator
157
158template <typename _Traits = CDebugAllocatorTraits>
159class CDebugAllocatorT
160{
161public:
162        typedef _Traits CTraits;
163
164        ////////////////////////////////////////////////////////
165        // CDescriptor
166
167        class CDescriptor
168        {
169        public:
170                SIZE_T m_nAllocationSize;
171                VOID* m_pvData;
172                SIZE_T m_nDataSize;
173                VOID* m_pvPaddingData;
174                SIZE_T m_nPaddingDataSize;
175
176        public:
177        // CDescriptor
178                static CDescriptor* Allocate(SIZE_T nDataSize)
179                {
180                        ATLASSERT(nDataSize > 0);
181                        const SIZE_T nPageSize = g_GlobalVirtualAllocator.GetPageSize();
182                        const SIZE_T nAlignedDataSize = g_GlobalVirtualAllocator.Align(nDataSize);
183                        const SIZE_T nAllocationSize = 
184                                g_GlobalVirtualAllocator.Align(sizeof (CDescriptor)) +
185                                CTraits::GetHeadSanityPageCount() * nPageSize +
186                                nAlignedDataSize +
187                                CTraits::GetTailSanityPageCount() * nPageSize +
188                                0;
189                        VOID* pvData = VirtualAlloc(NULL, nAllocationSize, MEM_COMMIT | MEM_RESERVE, PAGE_NOACCESS);
190                        ATLENSURE_THROW(pvData, AtlHresultFromLastError());
191                        CDescriptor* pDescriptor = (CDescriptor*) pvData;
192                        DWORD nCurrentProtection;
193                        ATLVERIFY(VirtualProtect(pDescriptor, sizeof *pDescriptor, PAGE_READWRITE, &nCurrentProtection));
194                        pDescriptor->m_nAllocationSize = nAllocationSize;
195                        pDescriptor->m_pvData = (BYTE*) pDescriptor + g_GlobalVirtualAllocator.Align(sizeof *pDescriptor) + CTraits::GetHeadSanityPageCount() * nPageSize;
196                        pDescriptor->m_nDataSize = nDataSize;
197                        const SIZE_T nPaddingDataSize = nAlignedDataSize - nDataSize;
198                        if(CTraits::IsHeadPadding() && nPaddingDataSize)
199                        {
200                                pDescriptor->m_pvPaddingData = pDescriptor->m_pvData;
201                                reinterpret_cast<BYTE*&>(pDescriptor->m_pvData) += nPaddingDataSize;
202                        } else
203                                pDescriptor->m_pvPaddingData = (BYTE*) pDescriptor->m_pvData + nAlignedDataSize - nPaddingDataSize;
204                        pDescriptor->m_nPaddingDataSize = nPaddingDataSize;
205                        ATLVERIFY(VirtualProtect(pDescriptor->m_pvData, pDescriptor->m_nDataSize, PAGE_READWRITE, &nCurrentProtection));
206                        memset(pDescriptor->m_pvPaddingData, 0x77, pDescriptor->m_nPaddingDataSize);
207                        ATLVERIFY(VirtualProtect(pDescriptor, sizeof *pDescriptor, PAGE_READONLY, &nCurrentProtection));
208                        return pDescriptor;
209                }
210                static CDescriptor* FromData(VOID* pvData)
211                {
212                        ATLASSERT(pvData);
213                        ATLASSERT(!(g_GlobalVirtualAllocator.GetPageSize() & (g_GlobalVirtualAllocator.GetPageSize() - 1)));
214                        BYTE* pnData = (BYTE*) ((UINT_PTR) pvData & ~(g_GlobalVirtualAllocator.GetPageSize() - 1));
215                        CDescriptor* pDescriptor = (CDescriptor*) (pnData - CTraits::GetHeadSanityPageCount() * g_GlobalVirtualAllocator.GetPageSize() - g_GlobalVirtualAllocator.Align(sizeof (CDescriptor)));
216                        return pDescriptor;
217                }
218                //VOID Initialize()
219                VOID Terminate()
220                {
221                        _ATLTRY
222                        {
223                                ATLENSURE_THROW(IsPaddingValid(), HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
224                        }
225                        _ATLCATCHALL()
226                        {
227                        }
228                        ATLVERIFY(VirtualFree(this, 0, MEM_RELEASE));
229                }
230                VOID* GetData() const throw()
231                {
232                        return m_pvData;
233                }
234                SIZE_T GetDataSize() const throw()
235                {
236                        return m_nDataSize;
237                }
238                BOOL IsPaddingValid() const throw()
239                {
240                        BYTE* pnPaddingData = (BYTE*) m_pvPaddingData;
241                        for(SIZE_T nIndex = m_nPaddingDataSize; nIndex > 0; nIndex--, pnPaddingData++)
242                                if(*pnPaddingData != 0x77)
243                                        return FALSE;
244                        return TRUE;
245                }
246        };
247
248public:
249// CDebugAllocator
250        static VOID* Allocate(_In_ SIZE_T nDataSize)
251        {
252                if(!nDataSize)
253                        return NULL;
254                CDescriptor* pDescriptor = CDescriptor::Allocate(nDataSize);
255                ATLASSERT(pDescriptor);
256                return pDescriptor->GetData();
257        }
258        static VOID* Reallocate(_In_opt_ VOID* pvData, _In_ SIZE_T nDataSize)
259        {
260                CDescriptor* pDescriptor;
261                if(pvData)
262                {
263                        pDescriptor = CDescriptor::FromData(pvData);
264                        if(nDataSize == pDescriptor->GetDataSize())
265                                return pvData;
266                } else
267                        pDescriptor = NULL;
268                VOID* pvNewData = NULL;
269                if(nDataSize)
270                {
271                        CDescriptor* pNewDescriptor = CDescriptor::Allocate(nDataSize);
272                        ATLASSERT(pNewDescriptor);
273                        _ATLTRY
274                        {
275                                if(pNewDescriptor && pDescriptor)
276                                {
277                                        SIZE_T nCopyDataSize = nDataSize;
278                                        if(nCopyDataSize > pDescriptor->GetDataSize())
279                                                nCopyDataSize = pDescriptor->GetDataSize();
280                                        Checked::memcpy_s(pNewDescriptor->GetData(), pNewDescriptor->GetDataSize(), pDescriptor->GetData(), nCopyDataSize);
281                                }
282                        }
283                        _ATLCATCHALL()
284                        {
285                                pNewDescriptor->Terminate();
286                                _ATLRETHROW;
287                        }
288                        pvNewData = pNewDescriptor->GetData();
289                }
290                if(pvData)
291                        Free(pvData);
292                return pvNewData;
293        }
294        static VOID Free(_In_opt_ VOID* pvData) throw()
295        {
296                if(!pvData)
297                        return;
298                CDescriptor* pDescriptor = CDescriptor::FromData(pvData);
299                ATLASSERT(pDescriptor);
300                pDescriptor->Terminate();
301        }
302};
303
304typedef CDebugAllocatorT<> CDebugAllocator;
305
306////////////////////////////////////////////////////////////
307// CVirtualHeapPtr
308
309template <typename T>
310class CDebugHeapPtr :
311        public CHeapPtr<T, CDebugAllocator>
312{
313public:
314// CDebugHeapPtr
315        CDebugHeapPtr() throw()
316        {
317        }
318        explicit CDebugHeapPtr(_In_ T* pData) throw() :
319                CHeapPtr<T, CDebugAllocator>(pData)
320        {
321        }
322        VOID SetProtection(DWORD nProtection)
323        {
324                if(!m_pData)
325                        return;
326                CDebugAllocator::CDescriptor* pDescriptor = CDebugAllocator::CDescriptor::FromData(m_pData);
327                ATLASSERT(pDescriptor);
328                DWORD nCurrentProtection;
329                ATLENSURE_THROW(VirtualProtect(pDescriptor->GetData(), pDescriptor->GetDataSize(), nProtection, &nCurrentProtection), AtlHresultFromLastError());
330        }
331};
332
Note: See TracBrowser for help on using the repository browser.