aboutsummaryrefslogtreecommitdiff
path: root/src/dutil/memutil.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2017-09-03 11:22:38 -0700
committerRob Mensching <rob@firegiant.com>2017-09-03 13:33:33 -0700
commit5d8375007754101ff2889d0e79486c8f9b7cf5ab (patch)
treea76d6fb6a38dd9f04a93ffcfd9d64e76779b3414 /src/dutil/memutil.cpp
parent8e8da6dbc051ec884b5d439bb4f44dc027d05bbf (diff)
downloadwix-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.cpp323
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
9static BOOL vfMemInitialized = FALSE;
10#endif
11
12extern "C" HRESULT DAPI MemInitialize()
13{
14#if DEBUG
15 vfMemInitialized = TRUE;
16#endif
17 return S_OK;
18}
19
20extern "C" void DAPI MemUninitialize()
21{
22#if DEBUG
23 vfMemInitialized = FALSE;
24#endif
25}
26
27extern "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
38extern "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
50extern "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
102LExit:
103 ReleaseMem(pvNew);
104
105 return hr;
106}
107
108
109extern "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
119extern "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
156LExit:
157 return hr;
158}
159
160
161extern "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
199LExit:
200 return hr;
201}
202
203
204extern "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
234LExit:
235 return hr;
236}
237
238extern "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
263extern "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
308extern "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
317extern "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}