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