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

Last change on this file since 36 was 36, checked in by roman, 11 years ago
  • Property svn:keywords set to Id
File size: 8.9 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2011
3// Created by Roman Ryltsov roman@alax.info
4//
5// $Id: VirtualHeapPtr.h 36 2011-11-05 20:45:20Z 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        static SIZE_T g_nHeadSanityPageCount;
141        static SIZE_T g_nTailSanityPageCount;
142
143public:
144// CDebugAllocatorTraits
145};
146
147__declspec(selectany) SIZE_T CDebugAllocatorTraits::g_nHeadSanityPageCount = 1;
148__declspec(selectany) SIZE_T CDebugAllocatorTraits::g_nTailSanityPageCount = 1;
149
150////////////////////////////////////////////////////////////
151// CDebugAllocatorT, CDebugAllocator
152
153template <typename _Traits = CDebugAllocatorTraits>
154class CDebugAllocatorT
155{
156public:
157        typedef _Traits CTraits;
158
159        ////////////////////////////////////////////////////////
160        // CDescriptor
161
162        class CDescriptor
163        {
164        public:
165                SIZE_T m_nAllocationSize;
166                VOID* m_pvData;
167                SIZE_T m_nDataSize;
168                VOID* m_pvPaddingData;
169                SIZE_T m_nPaddingDataSize;
170
171        public:
172        // CDescriptor
173                static CDescriptor* Allocate(SIZE_T nDataSize)
174                {
175                        ATLASSERT(nDataSize > 0);
176                        const SIZE_T nPageSize = g_GlobalVirtualAllocator.GetPageSize();
177                        const SIZE_T nAlignedDataSize = g_GlobalVirtualAllocator.Align(nDataSize);
178                        const SIZE_T nAllocationSize = 
179                                g_GlobalVirtualAllocator.Align(sizeof (CDescriptor)) +
180                                CTraits::g_nHeadSanityPageCount * nPageSize +
181                                nAlignedDataSize +
182                                CTraits::g_nTailSanityPageCount * nPageSize +
183                                0;
184                        VOID* pvData = VirtualAlloc(NULL, nAllocationSize, MEM_COMMIT | MEM_RESERVE, PAGE_NOACCESS);
185                        ATLENSURE_THROW(pvData, AtlHresultFromLastError());
186                        CDescriptor* pDescriptor = (CDescriptor*) pvData;
187                        DWORD nCurrentProtection;
188                        ATLVERIFY(VirtualProtect(pDescriptor, sizeof *pDescriptor, PAGE_READWRITE, &nCurrentProtection));
189                        pDescriptor->m_nAllocationSize = nAllocationSize;
190                        pDescriptor->m_pvData = (BYTE*) pDescriptor + g_GlobalVirtualAllocator.Align(sizeof *pDescriptor) + CTraits::g_nHeadSanityPageCount * nPageSize;
191                        pDescriptor->m_nDataSize = nDataSize;
192                        pDescriptor->m_nPaddingDataSize = nAlignedDataSize - nDataSize;
193                        pDescriptor->m_pvPaddingData = (BYTE*) pDescriptor->m_pvData + nAlignedDataSize - pDescriptor->m_nPaddingDataSize;
194                        ATLVERIFY(VirtualProtect(pDescriptor->m_pvData, pDescriptor->m_nDataSize, PAGE_READWRITE, &nCurrentProtection));
195                        memset(pDescriptor->m_pvPaddingData, 0x77, pDescriptor->m_nPaddingDataSize);
196                        ATLVERIFY(VirtualProtect(pDescriptor, sizeof *pDescriptor, PAGE_READONLY, &nCurrentProtection));
197                        return pDescriptor;
198                }
199                static CDescriptor* FromData(VOID* pvData)
200                {
201                        ATLASSERT(pvData);
202                        CDescriptor* pDescriptor = (CDescriptor*) ((BYTE*) pvData - CTraits::g_nHeadSanityPageCount * g_GlobalVirtualAllocator.GetPageSize() - g_GlobalVirtualAllocator.Align(sizeof (CDescriptor)));
203                        return pDescriptor;
204                }
205                //VOID Initialize()
206                VOID Terminate()
207                {
208                        _ATLTRY
209                        {
210                                ATLENSURE_THROW(IsPaddingValid(), HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
211                        }
212                        _ATLCATCHALL()
213                        {
214                        }
215                        ATLVERIFY(VirtualFree(this, 0, MEM_RELEASE));
216                }
217                VOID* GetData() const throw()
218                {
219                        return m_pvData;
220                }
221                SIZE_T GetDataSize() const throw()
222                {
223                        return m_nDataSize;
224                }
225                BOOL IsPaddingValid() const throw()
226                {
227                        BYTE* pnPaddingData = (BYTE*) m_pvPaddingData;
228                        for(SIZE_T nIndex = m_nPaddingDataSize; nIndex > 0; nIndex--, pnPaddingData++)
229                                if(*pnPaddingData != 0x77)
230                                        return FALSE;
231                        return TRUE;
232                }
233        };
234
235public:
236// CDebugAllocator
237        static VOID* Allocate(_In_ SIZE_T nDataSize)
238        {
239                if(!nDataSize)
240                        return NULL;
241                CDescriptor* pDescriptor = CDescriptor::Allocate(nDataSize);
242                ATLASSERT(pDescriptor);
243                return pDescriptor->GetData();
244        }
245        static VOID* Reallocate(_In_opt_ VOID* pvData, _In_ SIZE_T nDataSize)
246        {
247                CDescriptor* pDescriptor;
248                if(pvData)
249                {
250                        pDescriptor = CDescriptor::FromData(pvData);
251                        if(nDataSize == pDescriptor->GetDataSize())
252                                return pvData;
253                } else
254                        pDescriptor = NULL;
255                VOID* pvNewData = NULL;
256                if(nDataSize)
257                {
258                        CDescriptor* pNewDescriptor = CDescriptor::Allocate(nDataSize);
259                        ATLASSERT(pNewDescriptor);
260                        _ATLTRY
261                        {
262                                if(pNewDescriptor && pDescriptor)
263                                {
264                                        SIZE_T nCopyDataSize = nDataSize;
265                                        if(nCopyDataSize > pDescriptor->GetDataSize())
266                                                nCopyDataSize = pDescriptor->GetDataSize();
267                                        Checked::memcpy_s(pNewDescriptor->GetData(), pNewDescriptor->GetDataSize(), pDescriptor->GetData(), nCopyDataSize);
268                                }
269                        }
270                        _ATLCATCHALL()
271                        {
272                                pNewDescriptor->Terminate();
273                                _ATLRETHROW;
274                        }
275                        pvNewData = pNewDescriptor->GetData();
276                }
277                if(pvData)
278                        Free(pvData);
279                return pvNewData;
280        }
281        static VOID Free(_In_opt_ VOID* pvData) throw()
282        {
283                if(!pvData)
284                        return;
285                CDescriptor* pDescriptor = CDescriptor::FromData(pvData);
286                ATLASSERT(pDescriptor);
287                pDescriptor->Terminate();
288        }
289};
290
291typedef CDebugAllocatorT<> CDebugAllocator;
292
293////////////////////////////////////////////////////////////
294// CVirtualHeapPtr
295
296template <typename T>
297class CDebugHeapPtr :
298        public CHeapPtr<T, CDebugAllocator>
299{
300public:
301// CDebugHeapPtr
302        CDebugHeapPtr() throw()
303        {
304        }
305        explicit CDebugHeapPtr(_In_ T* pData) throw() :
306                CHeapPtr<T, CDebugAllocator>(pData)
307        {
308        }
309        VOID SetProtection(DWORD nProtection)
310        {
311                if(!m_pData)
312                        return;
313                CDebugAllocator::CDescriptor* pDescriptor = CDebugAllocator::CDescriptor::FromData(m_pData);
314                ATLASSERT(pDescriptor);
315                DWORD nCurrentProtection;
316                ATLENSURE_THROW(VirtualProtect(pDescriptor->GetData(), pDescriptor->GetDataSize(), nProtection, &nCurrentProtection), AtlHresultFromLastError());
317        }
318};
319
Note: See TracBrowser for help on using the repository browser.