diff options
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 | } | ||
