1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*++
6
7
8
9Module Name:
10
11 heap.c
12
13Abstract:
14
15 Implementation of heap memory management functions.
16
17Revision History:
18
19
20
21--*/
22
23#include "pal/palinternal.h"
24#include "pal/dbgmsg.h"
25#include "pal/handlemgr.hpp"
26#include "pal/corunix.hpp"
27#include <errno.h>
28using namespace CorUnix;
29
30SET_DEFAULT_DEBUG_CHANNEL(MEM);
31
32// In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable
33// defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement
34// should be placed after the SET_DEFAULT_DEBUG_CHANNEL(MEM)
35#include <safemath.h>
36
37#ifndef __APPLE__
38#define DUMMY_HEAP 0x01020304
39#endif // __APPLE__
40
41/*++
42Function:
43 RtlMoveMemory
44
45See MSDN doc.
46--*/
47VOID
48PALAPI
49RtlMoveMemory(
50 IN PVOID Destination,
51 IN CONST VOID *Source,
52 IN SIZE_T Length)
53{
54 PERF_ENTRY(RtlMoveMemory);
55 ENTRY("RtlMoveMemory(Destination:%p, Source:%p, Length:%d)\n",
56 Destination, Source, Length);
57
58 memmove(Destination, Source, Length);
59
60 LOGEXIT("RtlMoveMemory returning\n");
61 PERF_EXIT(RtlMoveMemory);
62}
63
64/*++
65Function:
66 HeapCreate
67
68See MSDN doc.
69--*/
70HANDLE
71PALAPI
72HeapCreate(
73 IN DWORD flOptions,
74 IN SIZE_T dwInitialSize,
75 IN SIZE_T dwMaximumSize)
76{
77 HANDLE ret = INVALID_HANDLE_VALUE;
78 PERF_ENTRY(HeapCreate);
79 ENTRY("HeapCreate(flOptions=%#x, dwInitialSize=%u, dwMaximumSize=%u)\n",
80 flOptions, dwInitialSize, dwMaximumSize);
81#ifdef __APPLE__
82 if ((flOptions & 0x40005) != 0)
83 {
84 ERROR("Invalid flOptions\n");
85 SetLastError(ERROR_INVALID_PARAMETER);
86 }
87 else if (flOptions != 0)
88 {
89 ERROR("No support for flOptions\n");
90 SetLastError(ERROR_INVALID_PARAMETER);
91 }
92 else if (dwMaximumSize)
93 {
94 ERROR("Zone implementation does not support a max size\n");
95 SetLastError(ERROR_INVALID_PARAMETER);
96 }
97 else
98 {
99 ret = (HANDLE)malloc_create_zone(dwInitialSize, 0 /* flags */);
100 }
101
102#else // __APPLE__
103 ret = (HANDLE)DUMMY_HEAP;
104#endif // __APPLE__
105
106 LOGEXIT("HeapCreate returning HANDLE %p\n", ret);
107 PERF_EXIT(HeapCreate);
108 return ret;
109}
110
111
112/*++
113Function:
114 GetProcessHeap
115
116See MSDN doc.
117--*/
118HANDLE
119PALAPI
120GetProcessHeap(
121 VOID)
122{
123 HANDLE ret;
124
125 PERF_ENTRY(GetProcessHeap);
126 ENTRY("GetProcessHeap()\n");
127
128#ifdef __APPLE__
129#if HEAP_HANDLES_ARE_REAL_HANDLES
130#error
131#else
132 malloc_zone_t *pZone = malloc_default_zone();
133 ret = (HANDLE)pZone;
134#endif // HEAP_HANDLES_ARE_REAL_HANDLES
135#else
136 ret = (HANDLE) DUMMY_HEAP;
137#endif
138
139 LOGEXIT("GetProcessHeap returning HANDLE %p\n", ret);
140 PERF_EXIT(GetProcessHeap);
141 return ret;
142}
143
144/*++
145Function:
146 HeapAlloc
147
148Abstract
149 Implemented as wrapper over malloc
150
151See MSDN doc.
152--*/
153LPVOID
154PALAPI
155HeapAlloc(
156 IN HANDLE hHeap,
157 IN DWORD dwFlags,
158 IN SIZE_T numberOfBytes)
159{
160 BYTE *pMem;
161
162 PERF_ENTRY(HeapAlloc);
163 ENTRY("HeapAlloc (hHeap=%p, dwFlags=%#x, numberOfBytes=%u)\n",
164 hHeap, dwFlags, numberOfBytes);
165
166#ifdef __APPLE__
167 if (hHeap == NULL)
168#else // __APPLE__
169 if (hHeap != (HANDLE) DUMMY_HEAP)
170#endif // __APPLE__ else
171 {
172 ERROR("Invalid heap handle\n");
173 SetLastError(ERROR_INVALID_PARAMETER);
174 LOGEXIT("HeapAlloc returning NULL\n");
175 PERF_EXIT(HeapAlloc);
176 return NULL;
177 }
178
179 if ((dwFlags != 0) && (dwFlags != HEAP_ZERO_MEMORY))
180 {
181 ASSERT("Invalid parameter dwFlags=%#x\n", dwFlags);
182 SetLastError(ERROR_INVALID_PARAMETER);
183 LOGEXIT("HeapAlloc returning NULL\n");
184 PERF_EXIT(HeapAlloc);
185 return NULL;
186 }
187
188#ifdef __APPLE__
189 // This is patterned off of InternalMalloc in malloc.cpp.
190 {
191 pMem = (BYTE *)malloc_zone_malloc((malloc_zone_t *)hHeap, numberOfBytes);
192 }
193#else // __APPLE__
194 pMem = (BYTE *) PAL_malloc(numberOfBytes);
195#endif // __APPLE__ else
196
197 if (pMem == NULL)
198 {
199 ERROR("Not enough memory\n");
200 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
201 LOGEXIT("HeapAlloc returning NULL\n");
202 PERF_EXIT(HeapAlloc);
203 return NULL;
204 }
205
206 /* If the HEAP_ZERO_MEMORY flag is set initialize to zero */
207 if (dwFlags == HEAP_ZERO_MEMORY)
208 {
209 memset(pMem, 0, numberOfBytes);
210 }
211
212 LOGEXIT("HeapAlloc returning LPVOID %p\n", pMem);
213 PERF_EXIT(HeapAlloc);
214 return (pMem);
215}
216
217
218/*++
219Function:
220 HeapFree
221
222Abstract
223 Implemented as wrapper over free
224
225See MSDN doc.
226--*/
227BOOL
228PALAPI
229HeapFree(
230 IN HANDLE hHeap,
231 IN DWORD dwFlags,
232 IN LPVOID lpMem)
233{
234 BOOL bRetVal = FALSE;
235
236 PERF_ENTRY(HeapFree);
237 ENTRY("HeapFree (hHeap=%p, dwFlags = %#x, lpMem=%p)\n",
238 hHeap, dwFlags, lpMem);
239
240#ifdef __APPLE__
241 if (hHeap == NULL)
242#else // __APPLE__
243 if (hHeap != (HANDLE) DUMMY_HEAP)
244#endif // __APPLE__ else
245 {
246 ERROR("Invalid heap handle\n");
247 SetLastError(ERROR_INVALID_PARAMETER);
248 goto done;
249 }
250
251 if (dwFlags != 0)
252 {
253 ASSERT("Invalid parameter dwFlags=%#x\n", dwFlags);
254 SetLastError(ERROR_INVALID_PARAMETER);
255 goto done;
256 }
257
258 if (!lpMem)
259 {
260 bRetVal = TRUE;
261 goto done;
262 }
263
264 bRetVal = TRUE;
265#ifdef __APPLE__
266 {
267 malloc_zone_free((malloc_zone_t *)hHeap, lpMem);
268 }
269#else // __APPLE__
270 PAL_free (lpMem);
271#endif // __APPLE__ else
272
273done:
274 LOGEXIT( "HeapFree returning BOOL %d\n", bRetVal );
275 PERF_EXIT(HeapFree);
276 return bRetVal;
277}
278
279
280/*++
281Function:
282 HeapReAlloc
283
284Abstract
285 Implemented as wrapper over realloc
286
287See MSDN doc.
288--*/
289LPVOID
290PALAPI
291HeapReAlloc(
292 IN HANDLE hHeap,
293 IN DWORD dwFlags,
294 IN LPVOID lpmem,
295 IN SIZE_T numberOfBytes)
296{
297 BYTE *pMem = NULL;
298
299 PERF_ENTRY(HeapReAlloc);
300 ENTRY("HeapReAlloc (hHeap=%p, dwFlags=%#x, lpmem=%p, numberOfBytes=%u)\n",
301 hHeap, dwFlags, lpmem, numberOfBytes);
302
303#ifdef __APPLE__
304 if (hHeap == NULL)
305#else // __APPLE__
306 if (hHeap != (HANDLE)DUMMY_HEAP)
307#endif // __APPLE__ else
308 {
309 ASSERT("Invalid heap handle\n");
310 SetLastError(ERROR_INVALID_HANDLE);
311 goto done;
312 }
313
314 if ((dwFlags != 0))
315 {
316 ASSERT("Invalid parameter dwFlags=%#x\n", dwFlags);
317 SetLastError(ERROR_INVALID_PARAMETER);
318 goto done;
319 }
320
321 if (lpmem == NULL)
322 {
323 WARN("NULL memory pointer to realloc. Do not do anything.\n");
324 /* set LastError back to zero. this appears to be an undocumented
325 behavior in Windows, in doesn't cost much to match it */
326 SetLastError(0);
327 goto done;
328 }
329
330 if(numberOfBytes == 0)
331 {
332 // PAL's realloc behaves like free for a requested size of zero bytes. Force a nonzero size to get a valid pointer.
333 numberOfBytes = 1;
334 }
335
336#ifdef __APPLE__
337 // This is patterned off of InternalRealloc in malloc.cpp.
338 {
339 pMem = (BYTE *) malloc_zone_realloc((malloc_zone_t *)hHeap, lpmem, numberOfBytes);
340 }
341#else // __APPLE__
342 pMem = (BYTE *) PAL_realloc(lpmem, numberOfBytes);
343#endif // __APPLE__ else
344
345 if (pMem == NULL)
346 {
347 ERROR("Not enough memory\n");
348 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
349 goto done;
350 }
351
352done:
353 LOGEXIT("HeapReAlloc returns LPVOID %p\n", pMem);
354 PERF_EXIT(HeapReAlloc);
355 return pMem;
356}
357
358BOOL
359PALAPI
360HeapSetInformation(
361 IN OPTIONAL HANDLE HeapHandle,
362 IN HEAP_INFORMATION_CLASS HeapInformationClass,
363 IN PVOID HeapInformation,
364 IN SIZE_T HeapInformationLength)
365{
366 return TRUE;
367}
368