1 /* 2 * PROJECT: ReactOS Spooler Router 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Functions for allocating and freeing memory 5 * COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org) 6 */ 7 8 #include "precomp.h" 9 10 11 /** 12 * @name AlignRpcPtr 13 * 14 * Checks if the input buffer and buffer size are 4-byte aligned. 15 * If the buffer size is not 4-byte aligned, it is aligned down. 16 * If the input buffer is not 4-byte aligned, a 4-byte aligned buffer of the aligned down buffer size is allocated and returned. 17 * 18 * @param pBuffer 19 * The buffer to check. 20 * 21 * @param pcbBuffer 22 * Pointer to the buffer size to check. Its value is aligned down if needed. 23 * 24 * @return 25 * pBuffer if pBuffer is already 4-byte aligned, or a newly allocated 4-byte aligned buffer of the aligned down buffer size otherwise. 26 * If a buffer was allocated, you have to free it using UndoAlignRpcPtr. 27 */ 28 PVOID WINAPI 29 AlignRpcPtr(PVOID pBuffer, PDWORD pcbBuffer) 30 { 31 ASSERT(pcbBuffer); 32 33 // Align down the buffer size in pcbBuffer to a 4-byte boundary. 34 *pcbBuffer -= *pcbBuffer % sizeof(DWORD); 35 36 // Check if pBuffer is 4-byte aligned. If not, allocate a 4-byte aligned buffer. 37 if ((ULONG_PTR)pBuffer % sizeof(DWORD)) 38 pBuffer = DllAllocSplMem(*pcbBuffer); 39 40 return pBuffer; 41 } 42 43 /** 44 * @name AllocSplStr 45 * 46 * Allocates memory for a Unicode string and copies the input string into it. 47 * Equivalent of wcsdup, but the returned buffer is allocated from the spooler heap and must be freed with DllFreeSplStr. 48 * 49 * @param pwszInput 50 * The input string to copy 51 * 52 * @return 53 * Pointer to the copied string or NULL if no memory could be allocated. 54 */ 55 PWSTR WINAPI 56 AllocSplStr(PCWSTR pwszInput) 57 { 58 DWORD cbInput; 59 PWSTR pwszOutput; 60 61 // Sanity check 62 if (!pwszInput) 63 return NULL; 64 65 // Get the length of the input string. 66 cbInput = (wcslen(pwszInput) + 1) * sizeof(WCHAR); 67 68 // Allocate it. We don't use DllAllocSplMem here, because it unnecessarily zeroes the memory. 69 pwszOutput = HeapAlloc(hProcessHeap, 0, cbInput); 70 if (!pwszOutput) 71 { 72 ERR("HeapAlloc failed!\n"); 73 return NULL; 74 } 75 76 // Copy the string and return it. 77 CopyMemory(pwszOutput, pwszInput, cbInput); 78 return pwszOutput; 79 } 80 81 /** 82 * @name DllAllocSplMem 83 * 84 * Allocate a block of zeroed memory. 85 * Windows allocates from a separate spooler heap here while we just use the process heap. 86 * 87 * @param dwBytes 88 * Number of bytes to allocate. 89 * 90 * @return 91 * A pointer to the allocated memory or NULL in case of an error. 92 * You have to free this memory using DllFreeSplMem. 93 */ 94 PVOID WINAPI 95 DllAllocSplMem(DWORD dwBytes) 96 { 97 return HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, dwBytes); 98 } 99 100 /** 101 * @name DllFreeSplMem 102 * 103 * Frees the memory allocated with DllAllocSplMem. 104 * 105 * @param pMem 106 * Pointer to the allocated memory. 107 * 108 * @return 109 * TRUE in case of success, FALSE otherwise. 110 */ 111 BOOL WINAPI 112 DllFreeSplMem(PVOID pMem) 113 { 114 return HeapFree(hProcessHeap, 0, pMem); 115 } 116 117 /** 118 * @name DllFreeSplStr 119 * 120 * Frees the string allocated with AllocSplStr. 121 * 122 * @param pwszString 123 * Pointer to the allocated string. 124 * 125 * @return 126 * TRUE in case of success, FALSE otherwise. 127 */ 128 BOOL WINAPI 129 DllFreeSplStr(PWSTR pwszString) 130 { 131 return HeapFree(hProcessHeap, 0, pwszString); 132 } 133 134 /** 135 * @name ReallocSplMem 136 * 137 * Allocates a new block of memory and copies the contents of the old block into the new one. 138 * 139 * @param pOldMem 140 * Pointer to the old block of memory. 141 * If this parameter is NULL, ReallocSplMem behaves exactly like DllAllocSplMem. 142 * 143 * @param cbOld 144 * Number of bytes to copy from the old block into the new one. 145 * 146 * @param cbNew 147 * Number of bytes to allocate for the new block. 148 * 149 * @return 150 * A pointer to the allocated new block or NULL in case of an error. 151 * You have to free this memory using DllFreeSplMem. 152 */ 153 PVOID WINAPI 154 ReallocSplMem(PVOID pOldMem, DWORD cbOld, DWORD cbNew) 155 { 156 PVOID pNewMem; 157 158 // Always allocate the new block of memory. 159 pNewMem = DllAllocSplMem(cbNew); 160 if (!pNewMem) 161 { 162 ERR("DllAllocSplMem failed!\n"); 163 return NULL; 164 } 165 166 // Copy the old memory into the new block and free it. 167 if (pOldMem) 168 { 169 CopyMemory(pNewMem, pOldMem, min(cbOld, cbNew)); 170 DllFreeSplMem(pOldMem); 171 } 172 173 return pNewMem; 174 } 175 176 /** 177 * @name ReallocSplStr 178 * 179 * Frees a string allocated by AllocSplStr and copies the given Unicode string into a newly allocated block of memory. 180 * 181 * @param ppwszString 182 * Pointer to the string pointer allocated by AllocSplStr. 183 * When the function returns, the variable receives the pointer to the copied string. 184 * 185 * @param pwszInput 186 * The Unicode string to copy into the new block of memory. 187 * 188 * @return 189 * Returns TRUE in any case. 190 */ 191 BOOL WINAPI 192 ReallocSplStr(PWSTR* ppwszString, PCWSTR pwszInput) 193 { 194 if (*ppwszString) 195 DllFreeSplStr(*ppwszString); 196 197 *ppwszString = AllocSplStr(pwszInput); 198 199 return TRUE; 200 } 201 202 /** 203 * @name UndoAlignRpcPtr 204 * 205 * Copies the data from the aligned buffer previously allocated by AlignRpcPtr back to the original unaligned buffer. 206 * The aligned buffer is freed. 207 * 208 * Also aligns up the returned required buffer size of a function to a 4-byte boundary. 209 * 210 * @param pDestinationBuffer 211 * The original unaligned buffer, which you input as pBuffer to AlignRpcPtr. 212 * The data from pSourceBuffer is copied into this buffer before pSourceBuffer is freed. 213 * If AlignRpcPtr did not allocate a buffer, pDestinationBuffer equals pSourceBuffer and no memory is copied or freed. 214 * This parameter may be NULL if pSourceBuffer is NULL or cbBuffer is 0. 215 * 216 * @param pSourceBuffer 217 * The aligned buffer, which is returned by AlignRpcPtr. 218 * Its data is copied into pDestinationBuffer and then pSourceBuffer is freed. 219 * If AlignRpcPtr did not allocate a buffer, pDestinationBuffer equals pSourceBuffer and no memory is copied or freed. 220 * This parameter may be NULL. 221 * 222 * @param cbBuffer 223 * Number of bytes to copy. 224 * Set this to the size returned by AlignRpcPtr's pcbBuffer or less. 225 * 226 * @param pcbNeeded 227 * Let this parameter point to your variable calculating the needed bytes for a buffer and returning this value to the user. 228 * It is then aligned up to a 4-byte boundary, so that the user supplies a large enough buffer in the next call. 229 * Otherwise, AlignRpcPtr would align down the buffer size in the next call and your buffer would be smaller than intended. 230 * This parameter may be NULL. 231 * 232 * @return 233 * pcbNeeded 234 */ 235 PDWORD WINAPI 236 UndoAlignRpcPtr(PVOID pDestinationBuffer, PVOID pSourceBuffer, DWORD cbBuffer, PDWORD pcbNeeded) 237 { 238 // pDestinationBuffer is accessed unless pSourceBuffer equals pDestinationBuffer or cbBuffer is 0. 239 ASSERT(pDestinationBuffer || pSourceBuffer == pDestinationBuffer || cbBuffer == 0); 240 241 // If pSourceBuffer is given, and source and destination pointers don't match, 242 // we assume that pSourceBuffer is the buffer allocated by AlignRpcPtr. 243 if (pSourceBuffer && pSourceBuffer != pDestinationBuffer) 244 { 245 // Copy back the buffer data to the (usually unaligned) destination buffer 246 // and free the buffer allocated by AlignRpcPtr. 247 CopyMemory(pDestinationBuffer, pSourceBuffer, cbBuffer); 248 DllFreeSplMem(pSourceBuffer); 249 } 250 251 // If pcbNeeded is given, align it up to a 4-byte boundary. 252 if (pcbNeeded && *pcbNeeded % sizeof(DWORD)) 253 *pcbNeeded += sizeof(DWORD) - *pcbNeeded % sizeof(DWORD); 254 255 return pcbNeeded; 256 } 257