diff options
author | Rob Mensching <rob@firegiant.com> | 2017-09-03 11:22:38 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2017-09-03 13:33:33 -0700 |
commit | 5d8375007754101ff2889d0e79486c8f9b7cf5ab (patch) | |
tree | a76d6fb6a38dd9f04a93ffcfd9d64e76779b3414 /src/dutil/memutil.cpp | |
parent | 8e8da6dbc051ec884b5d439bb4f44dc027d05bbf (diff) | |
download | wix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.tar.gz wix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.tar.bz2 wix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.zip |
Initial commit
Diffstat (limited to 'src/dutil/memutil.cpp')
-rw-r--r-- | src/dutil/memutil.cpp | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/src/dutil/memutil.cpp b/src/dutil/memutil.cpp new file mode 100644 index 00000000..578c65ee --- /dev/null +++ b/src/dutil/memutil.cpp | |||
@@ -0,0 +1,323 @@ | |||
1 | #pragma once | ||
2 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
3 | |||
4 | |||
5 | #include "precomp.h" | ||
6 | |||
7 | |||
8 | #if DEBUG | ||
9 | static BOOL vfMemInitialized = FALSE; | ||
10 | #endif | ||
11 | |||
12 | extern "C" HRESULT DAPI MemInitialize() | ||
13 | { | ||
14 | #if DEBUG | ||
15 | vfMemInitialized = TRUE; | ||
16 | #endif | ||
17 | return S_OK; | ||
18 | } | ||
19 | |||
20 | extern "C" void DAPI MemUninitialize() | ||
21 | { | ||
22 | #if DEBUG | ||
23 | vfMemInitialized = FALSE; | ||
24 | #endif | ||
25 | } | ||
26 | |||
27 | extern "C" LPVOID DAPI MemAlloc( | ||
28 | __in SIZE_T cbSize, | ||
29 | __in BOOL fZero | ||
30 | ) | ||
31 | { | ||
32 | // AssertSz(vfMemInitialized, "MemInitialize() not called, this would normally crash"); | ||
33 | AssertSz(0 < cbSize, "MemAlloc() called with invalid size"); | ||
34 | return ::HeapAlloc(::GetProcessHeap(), fZero ? HEAP_ZERO_MEMORY : 0, cbSize); | ||
35 | } | ||
36 | |||
37 | |||
38 | extern "C" LPVOID DAPI MemReAlloc( | ||
39 | __in LPVOID pv, | ||
40 | __in SIZE_T cbSize, | ||
41 | __in BOOL fZero | ||
42 | ) | ||
43 | { | ||
44 | // AssertSz(vfMemInitialized, "MemInitialize() not called, this would normally crash"); | ||
45 | AssertSz(0 < cbSize, "MemReAlloc() called with invalid size"); | ||
46 | return ::HeapReAlloc(::GetProcessHeap(), fZero ? HEAP_ZERO_MEMORY : 0, pv, cbSize); | ||
47 | } | ||
48 | |||
49 | |||
50 | extern "C" HRESULT DAPI MemReAllocSecure( | ||
51 | __in LPVOID pv, | ||
52 | __in SIZE_T cbSize, | ||
53 | __in BOOL fZero, | ||
54 | __out LPVOID* ppvNew | ||
55 | ) | ||
56 | { | ||
57 | // AssertSz(vfMemInitialized, "MemInitialize() not called, this would normally crash"); | ||
58 | AssertSz(ppvNew, "MemReAllocSecure() called with uninitialized pointer"); | ||
59 | AssertSz(0 < cbSize, "MemReAllocSecure() called with invalid size"); | ||
60 | |||
61 | HRESULT hr = S_OK; | ||
62 | DWORD dwFlags = HEAP_REALLOC_IN_PLACE_ONLY; | ||
63 | LPVOID pvNew = NULL; | ||
64 | |||
65 | dwFlags |= fZero ? HEAP_ZERO_MEMORY : 0; | ||
66 | pvNew = ::HeapReAlloc(::GetProcessHeap(), dwFlags, pv, cbSize); | ||
67 | if (!pvNew) | ||
68 | { | ||
69 | pvNew = MemAlloc(cbSize, fZero); | ||
70 | if (pvNew) | ||
71 | { | ||
72 | const SIZE_T cbCurrent = MemSize(pv); | ||
73 | if (-1 == cbCurrent) | ||
74 | { | ||
75 | ExitOnFailure(hr = E_INVALIDARG, "Failed to get memory size"); | ||
76 | } | ||
77 | |||
78 | // HeapReAlloc may allocate more memory than requested. | ||
79 | const SIZE_T cbNew = MemSize(pvNew); | ||
80 | if (-1 == cbNew) | ||
81 | { | ||
82 | ExitOnFailure(hr = E_INVALIDARG, "Failed to get memory size"); | ||
83 | } | ||
84 | |||
85 | cbSize = cbNew; | ||
86 | if (cbSize > cbCurrent) | ||
87 | { | ||
88 | cbSize = cbCurrent; | ||
89 | } | ||
90 | |||
91 | memcpy_s(pvNew, cbNew, pv, cbSize); | ||
92 | |||
93 | SecureZeroMemory(pv, cbCurrent); | ||
94 | MemFree(pv); | ||
95 | } | ||
96 | } | ||
97 | ExitOnNull(pvNew, hr, E_OUTOFMEMORY, "Failed to reallocate memory"); | ||
98 | |||
99 | *ppvNew = pvNew; | ||
100 | pvNew = NULL; | ||
101 | |||
102 | LExit: | ||
103 | ReleaseMem(pvNew); | ||
104 | |||
105 | return hr; | ||
106 | } | ||
107 | |||
108 | |||
109 | extern "C" HRESULT DAPI MemAllocArray( | ||
110 | __inout LPVOID* ppvArray, | ||
111 | __in SIZE_T cbArrayType, | ||
112 | __in DWORD dwItemCount | ||
113 | ) | ||
114 | { | ||
115 | return MemReAllocArray(ppvArray, 0, cbArrayType, dwItemCount); | ||
116 | } | ||
117 | |||
118 | |||
119 | extern "C" HRESULT DAPI MemReAllocArray( | ||
120 | __inout LPVOID* ppvArray, | ||
121 | __in DWORD cArray, | ||
122 | __in SIZE_T cbArrayType, | ||
123 | __in DWORD dwNewItemCount | ||
124 | ) | ||
125 | { | ||
126 | HRESULT hr = S_OK; | ||
127 | DWORD cNew = 0; | ||
128 | LPVOID pvNew = NULL; | ||
129 | SIZE_T cbNew = 0; | ||
130 | |||
131 | hr = ::DWordAdd(cArray, dwNewItemCount, &cNew); | ||
132 | ExitOnFailure(hr, "Integer overflow when calculating new element count."); | ||
133 | |||
134 | hr = ::SIZETMult(cNew, cbArrayType, &cbNew); | ||
135 | ExitOnFailure(hr, "Integer overflow when calculating new block size."); | ||
136 | |||
137 | if (*ppvArray) | ||
138 | { | ||
139 | SIZE_T cbCurrent = MemSize(*ppvArray); | ||
140 | if (cbCurrent < cbNew) | ||
141 | { | ||
142 | pvNew = MemReAlloc(*ppvArray, cbNew, TRUE); | ||
143 | ExitOnNull(pvNew, hr, E_OUTOFMEMORY, "Failed to allocate larger array."); | ||
144 | |||
145 | *ppvArray = pvNew; | ||
146 | } | ||
147 | } | ||
148 | else | ||
149 | { | ||
150 | pvNew = MemAlloc(cbNew, TRUE); | ||
151 | ExitOnNull(pvNew, hr, E_OUTOFMEMORY, "Failed to allocate new array."); | ||
152 | |||
153 | *ppvArray = pvNew; | ||
154 | } | ||
155 | |||
156 | LExit: | ||
157 | return hr; | ||
158 | } | ||
159 | |||
160 | |||
161 | extern "C" HRESULT DAPI MemEnsureArraySize( | ||
162 | __deref_out_bcount(cArray * cbArrayType) LPVOID* ppvArray, | ||
163 | __in DWORD cArray, | ||
164 | __in SIZE_T cbArrayType, | ||
165 | __in DWORD dwGrowthCount | ||
166 | ) | ||
167 | { | ||
168 | HRESULT hr = S_OK; | ||
169 | DWORD cNew = 0; | ||
170 | LPVOID pvNew = NULL; | ||
171 | SIZE_T cbNew = 0; | ||
172 | |||
173 | hr = ::DWordAdd(cArray, dwGrowthCount, &cNew); | ||
174 | ExitOnFailure(hr, "Integer overflow when calculating new element count."); | ||
175 | |||
176 | hr = ::SIZETMult(cNew, cbArrayType, &cbNew); | ||
177 | ExitOnFailure(hr, "Integer overflow when calculating new block size."); | ||
178 | |||
179 | if (*ppvArray) | ||
180 | { | ||
181 | SIZE_T cbUsed = cArray * cbArrayType; | ||
182 | SIZE_T cbCurrent = MemSize(*ppvArray); | ||
183 | if (cbCurrent < cbUsed) | ||
184 | { | ||
185 | pvNew = MemReAlloc(*ppvArray, cbNew, TRUE); | ||
186 | ExitOnNull(pvNew, hr, E_OUTOFMEMORY, "Failed to allocate array larger."); | ||
187 | |||
188 | *ppvArray = pvNew; | ||
189 | } | ||
190 | } | ||
191 | else | ||
192 | { | ||
193 | pvNew = MemAlloc(cbNew, TRUE); | ||
194 | ExitOnNull(pvNew, hr, E_OUTOFMEMORY, "Failed to allocate new array."); | ||
195 | |||
196 | *ppvArray = pvNew; | ||
197 | } | ||
198 | |||
199 | LExit: | ||
200 | return hr; | ||
201 | } | ||
202 | |||
203 | |||
204 | extern "C" HRESULT DAPI MemInsertIntoArray( | ||
205 | __deref_out_bcount((cExistingArray + cInsertItems) * cbArrayType) LPVOID* ppvArray, | ||
206 | __in DWORD dwInsertIndex, | ||
207 | __in DWORD cInsertItems, | ||
208 | __in DWORD cExistingArray, | ||
209 | __in SIZE_T cbArrayType, | ||
210 | __in DWORD dwGrowthCount | ||
211 | ) | ||
212 | { | ||
213 | HRESULT hr = S_OK; | ||
214 | DWORD i; | ||
215 | BYTE *pbArray = NULL; | ||
216 | |||
217 | if (0 == cInsertItems) | ||
218 | { | ||
219 | ExitFunction1(hr = S_OK); | ||
220 | } | ||
221 | |||
222 | hr = MemEnsureArraySize(ppvArray, cExistingArray + cInsertItems, cbArrayType, dwGrowthCount); | ||
223 | ExitOnFailure(hr, "Failed to resize array while inserting items"); | ||
224 | |||
225 | pbArray = reinterpret_cast<BYTE *>(*ppvArray); | ||
226 | for (i = cExistingArray + cInsertItems - 1; i > dwInsertIndex; --i) | ||
227 | { | ||
228 | memcpy_s(pbArray + i * cbArrayType, cbArrayType, pbArray + (i - 1) * cbArrayType, cbArrayType); | ||
229 | } | ||
230 | |||
231 | // Zero out the newly-inserted items | ||
232 | memset(pbArray + dwInsertIndex * cbArrayType, 0, cInsertItems * cbArrayType); | ||
233 | |||
234 | LExit: | ||
235 | return hr; | ||
236 | } | ||
237 | |||
238 | extern "C" void DAPI MemRemoveFromArray( | ||
239 | __inout_bcount((cExistingArray + cInsertItems) * cbArrayType) LPVOID pvArray, | ||
240 | __in DWORD dwRemoveIndex, | ||
241 | __in DWORD cRemoveItems, | ||
242 | __in DWORD cExistingArray, | ||
243 | __in SIZE_T cbArrayType, | ||
244 | __in BOOL fPreserveOrder | ||
245 | ) | ||
246 | { | ||
247 | BYTE *pbArray = static_cast<BYTE *>(pvArray); | ||
248 | DWORD cItemsLeftAfterRemoveIndex = (cExistingArray - cRemoveItems - dwRemoveIndex); | ||
249 | |||
250 | if (fPreserveOrder) | ||
251 | { | ||
252 | memmove(pbArray + dwRemoveIndex * cbArrayType, pbArray + (dwRemoveIndex + cRemoveItems) * cbArrayType, cItemsLeftAfterRemoveIndex * cbArrayType); | ||
253 | } | ||
254 | else | ||
255 | { | ||
256 | DWORD cItemsToMove = (cRemoveItems > cItemsLeftAfterRemoveIndex ? cItemsLeftAfterRemoveIndex : cRemoveItems); | ||
257 | memmove(pbArray + dwRemoveIndex * cbArrayType, pbArray + (cExistingArray - cItemsToMove) * cbArrayType, cItemsToMove * cbArrayType); | ||
258 | } | ||
259 | |||
260 | ZeroMemory(pbArray + (cExistingArray - cRemoveItems) * cbArrayType, cRemoveItems * cbArrayType); | ||
261 | } | ||
262 | |||
263 | extern "C" void DAPI MemArraySwapItems( | ||
264 | __inout_bcount((cExistingArray) * cbArrayType) LPVOID pvArray, | ||
265 | __in DWORD dwIndex1, | ||
266 | __in DWORD dwIndex2, | ||
267 | __in SIZE_T cbArrayType | ||
268 | ) | ||
269 | { | ||
270 | BYTE *pbArrayItem1 = static_cast<BYTE *>(pvArray) + dwIndex1 * cbArrayType; | ||
271 | BYTE *pbArrayItem2 = static_cast<BYTE *>(pvArray) + dwIndex2 * cbArrayType; | ||
272 | DWORD dwByteIndex = 0; | ||
273 | |||
274 | if (dwIndex1 == dwIndex2) | ||
275 | { | ||
276 | return; | ||
277 | } | ||
278 | |||
279 | // Use XOR swapping to avoid the need for a temporary item | ||
280 | while (dwByteIndex < cbArrayType) | ||
281 | { | ||
282 | // Try to do many bytes at a time in most cases | ||
283 | if (cbArrayType - dwByteIndex > sizeof(DWORD64)) | ||
284 | { | ||
285 | // x: X xor Y | ||
286 | *(reinterpret_cast<DWORD64 *>(pbArrayItem1 + dwByteIndex)) ^= *(reinterpret_cast<DWORD64 *>(pbArrayItem2 + dwByteIndex)); | ||
287 | // y: X xor Y | ||
288 | *(reinterpret_cast<DWORD64 *>(pbArrayItem2 + dwByteIndex)) = *(reinterpret_cast<DWORD64 *>(pbArrayItem1 + dwByteIndex)) ^ *(reinterpret_cast<DWORD64 *>(pbArrayItem2 + dwByteIndex)); | ||
289 | // x: X xor Y | ||
290 | *(reinterpret_cast<DWORD64 *>(pbArrayItem1 + dwByteIndex)) ^= *(reinterpret_cast<DWORD64 *>(pbArrayItem2 + dwByteIndex)); | ||
291 | |||
292 | dwByteIndex += sizeof(DWORD64); | ||
293 | } | ||
294 | else | ||
295 | { | ||
296 | // x: X xor Y | ||
297 | *(reinterpret_cast<unsigned char *>(pbArrayItem1 + dwByteIndex)) ^= *(reinterpret_cast<unsigned char *>(pbArrayItem2 + dwByteIndex)); | ||
298 | // y: X xor Y | ||
299 | *(reinterpret_cast<unsigned char *>(pbArrayItem2 + dwByteIndex)) = *(reinterpret_cast<unsigned char *>(pbArrayItem1 + dwByteIndex)) ^ *(reinterpret_cast<unsigned char *>(pbArrayItem2 + dwByteIndex)); | ||
300 | // x: X xor Y | ||
301 | *(reinterpret_cast<unsigned char *>(pbArrayItem1 + dwByteIndex)) ^= *(reinterpret_cast<unsigned char *>(pbArrayItem2 + dwByteIndex)); | ||
302 | |||
303 | dwByteIndex += sizeof(unsigned char); | ||
304 | } | ||
305 | } | ||
306 | } | ||
307 | |||
308 | extern "C" HRESULT DAPI MemFree( | ||
309 | __in LPVOID pv | ||
310 | ) | ||
311 | { | ||
312 | // AssertSz(vfMemInitialized, "MemInitialize() not called, this would normally crash"); | ||
313 | return ::HeapFree(::GetProcessHeap(), 0, pv) ? S_OK : HRESULT_FROM_WIN32(::GetLastError()); | ||
314 | } | ||
315 | |||
316 | |||
317 | extern "C" SIZE_T DAPI MemSize( | ||
318 | __in LPCVOID pv | ||
319 | ) | ||
320 | { | ||
321 | // AssertSz(vfMemInitialized, "MemInitialize() not called, this would normally crash"); | ||
322 | return ::HeapSize(::GetProcessHeap(), 0, pv); | ||
323 | } | ||