Merge pull request #2890 from sivarv/master
[platform/upstream/coreclr.git] / src / pal / src / memory / heap.cpp
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
9 Module Name:
10
11     heap.c
12
13 Abstract:
14
15     Implementation of heap memory management functions.
16
17 Revision 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>
28 using namespace CorUnix;
29
30 SET_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 /*++
42 Function:
43   RtlMoveMemory
44
45 See MSDN doc.
46 --*/
47 VOID
48 PALAPI
49 RtlMoveMemory(
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 /*++
65 Function:
66   RtlZeroMemory
67
68 See MSDN doc.
69 --*/
70 VOID
71 PALAPI
72 RtlZeroMemory(
73     PVOID Destination,
74     SIZE_T Length
75 )
76 {
77     PERF_ENTRY(RtlZeroMemory);
78     ENTRY("RtlZeroMemory(Destination:%p, Length:%x)\n", Destination, Length);
79     
80     memset(Destination, 0, Length);
81     
82     LOGEXIT("RtlZeroMemory returning.\n");
83     PERF_EXIT(RtlZeroMemory);
84 }
85
86 /*++
87 Function:
88   HeapCreate
89
90 See MSDN doc.
91 --*/
92 HANDLE
93 PALAPI
94 HeapCreate(
95                IN DWORD flOptions,
96                IN SIZE_T dwInitialSize,
97                IN SIZE_T dwMaximumSize)
98 {
99     HANDLE ret = INVALID_HANDLE_VALUE;
100     PERF_ENTRY(HeapCreate);
101     ENTRY("HeapCreate(flOptions=%#x, dwInitialSize=%u, dwMaximumSize=%u)\n",
102         flOptions, dwInitialSize, dwMaximumSize);
103 #ifdef __APPLE__
104     if ((flOptions & 0x40005) != 0)
105     {
106         ERROR("Invalid flOptions\n");
107         SetLastError(ERROR_INVALID_PARAMETER);
108     }
109     else if (flOptions != 0)
110     {
111         ERROR("No support for flOptions\n");
112         SetLastError(ERROR_INVALID_PARAMETER);
113     }
114     else if (dwMaximumSize)
115     {
116         ERROR("Zone implementation does not support a max size\n");
117         SetLastError(ERROR_INVALID_PARAMETER);
118     }
119     else
120     {
121         ret = (HANDLE)malloc_create_zone(dwInitialSize, 0 /* flags */);
122     }
123     
124 #else // __APPLE__
125     ret = (HANDLE)DUMMY_HEAP;
126 #endif // __APPLE__
127
128     LOGEXIT("HeapCreate returning HANDLE %p\n", ret);
129     PERF_EXIT(HeapCreate);
130     return ret;
131 }
132
133
134 /*++
135 Function:
136   GetProcessHeap
137
138 See MSDN doc.
139 --*/
140 HANDLE
141 PALAPI
142 GetProcessHeap(
143                VOID)
144 {
145     HANDLE ret;
146
147     PERF_ENTRY(GetProcessHeap);
148     ENTRY("GetProcessHeap()\n");
149
150 #ifdef __APPLE__
151 #if HEAP_HANDLES_ARE_REAL_HANDLES
152 #error
153 #else
154     malloc_zone_t *pZone = malloc_default_zone();
155     ret = (HANDLE)pZone;
156 #endif // HEAP_HANDLES_ARE_REAL_HANDLES
157 #else
158     ret = (HANDLE) DUMMY_HEAP;
159 #endif
160   
161     LOGEXIT("GetProcessHeap returning HANDLE %p\n", ret);
162     PERF_EXIT(GetProcessHeap);
163     return ret;
164 }
165
166 /*++
167 Function:
168   HeapAlloc
169
170 Abstract
171   Implemented as wrapper over malloc
172
173 See MSDN doc.
174 --*/
175 LPVOID
176 PALAPI
177 HeapAlloc(
178     IN HANDLE hHeap,
179     IN DWORD dwFlags,
180     IN SIZE_T numberOfBytes)
181 {
182     BYTE *pMem;
183
184     PERF_ENTRY(HeapAlloc);
185     ENTRY("HeapAlloc (hHeap=%p, dwFlags=%#x, numberOfBytes=%u)\n",
186           hHeap, dwFlags, numberOfBytes);
187
188 #ifdef __APPLE__
189     if (hHeap == NULL)
190 #else // __APPLE__
191     if (hHeap != (HANDLE) DUMMY_HEAP)
192 #endif // __APPLE__ else
193     {
194         ERROR("Invalid heap handle\n");
195         SetLastError(ERROR_INVALID_PARAMETER);
196         LOGEXIT("HeapAlloc returning NULL\n");
197         PERF_EXIT(HeapAlloc);
198         return NULL;
199     }
200
201     if ((dwFlags != 0) && (dwFlags != HEAP_ZERO_MEMORY))
202     {
203         ASSERT("Invalid parameter dwFlags=%#x\n", dwFlags);
204         SetLastError(ERROR_INVALID_PARAMETER);
205         LOGEXIT("HeapAlloc returning NULL\n");
206         PERF_EXIT(HeapAlloc);
207         return NULL;
208     }
209
210 #ifdef __APPLE__
211     // This is patterned off of InternalMalloc in malloc.cpp.
212     {
213         pMem = (BYTE *)malloc_zone_malloc((malloc_zone_t *)hHeap, numberOfBytes);
214     }
215 #else // __APPLE__
216     pMem = (BYTE *) PAL_malloc(numberOfBytes);
217 #endif // __APPLE__ else
218
219     if (pMem == NULL)
220     {
221         ERROR("Not enough memory\n");
222         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
223         LOGEXIT("HeapAlloc returning NULL\n");
224         PERF_EXIT(HeapAlloc);
225         return NULL;
226     }
227
228     /* If the HEAP_ZERO_MEMORY flag is set initialize to zero */
229     if (dwFlags == HEAP_ZERO_MEMORY)
230     {
231         memset(pMem, 0, numberOfBytes);
232     }
233
234     LOGEXIT("HeapAlloc returning LPVOID %p\n", pMem);
235     PERF_EXIT(HeapAlloc);
236     return (pMem);
237 }
238
239
240 /*++
241 Function:
242   HeapFree
243
244 Abstract
245   Implemented as wrapper over free
246
247 See MSDN doc.
248 --*/
249 BOOL
250 PALAPI
251 HeapFree(
252     IN HANDLE hHeap,
253     IN DWORD dwFlags,
254     IN LPVOID lpMem)
255 {
256     BOOL bRetVal = FALSE;
257
258     PERF_ENTRY(HeapFree);
259     ENTRY("HeapFree (hHeap=%p, dwFlags = %#x, lpMem=%p)\n", 
260           hHeap, dwFlags, lpMem);
261
262 #ifdef __APPLE__
263     if (hHeap == NULL)
264 #else // __APPLE__
265     if (hHeap != (HANDLE) DUMMY_HEAP)
266 #endif // __APPLE__ else
267     {
268         ERROR("Invalid heap handle\n");
269         SetLastError(ERROR_INVALID_PARAMETER);
270         goto done;
271     }
272
273     if (dwFlags != 0)
274     {
275         ASSERT("Invalid parameter dwFlags=%#x\n", dwFlags);
276         SetLastError(ERROR_INVALID_PARAMETER);
277         goto done;
278     }
279
280     if (!lpMem)
281     {
282         bRetVal = TRUE;
283         goto done;
284     }
285
286     bRetVal = TRUE;
287 #ifdef __APPLE__
288     // This is patterned off of InternalFree in malloc.cpp.
289     {
290         malloc_zone_free((malloc_zone_t *)hHeap, lpMem);
291     }
292 #else // __APPLE__
293     PAL_free (lpMem);
294 #endif // __APPLE__ else
295
296 done:
297     LOGEXIT( "HeapFree returning BOOL %d\n", bRetVal );
298     PERF_EXIT(HeapFree);
299     return bRetVal;
300 }
301
302
303 /*++
304 Function:
305   HeapReAlloc
306
307 Abstract
308   Implemented as wrapper over realloc
309
310 See MSDN doc.
311 --*/
312 LPVOID
313 PALAPI
314 HeapReAlloc(
315     IN HANDLE hHeap,
316     IN DWORD dwFlags,
317     IN LPVOID lpmem,
318     IN SIZE_T numberOfBytes)
319 {
320     BYTE *pMem = NULL;
321
322     PERF_ENTRY(HeapReAlloc);
323     ENTRY("HeapReAlloc (hHeap=%p, dwFlags=%#x, lpmem=%p, numberOfBytes=%u)\n",
324           hHeap, dwFlags, lpmem, numberOfBytes);
325
326 #ifdef __APPLE__
327     if (hHeap == NULL)
328 #else // __APPLE__
329     if (hHeap != (HANDLE)DUMMY_HEAP)
330 #endif // __APPLE__ else
331     {
332         ASSERT("Invalid heap handle\n");
333         SetLastError(ERROR_INVALID_HANDLE);
334         goto done;
335     }
336
337     if ((dwFlags != 0))
338     {
339         ASSERT("Invalid parameter dwFlags=%#x\n", dwFlags);
340         SetLastError(ERROR_INVALID_PARAMETER);
341         goto done;
342     }
343
344     if (lpmem == NULL)
345     {
346         WARN("NULL memory pointer to realloc. Do not do anything.\n");
347         /* set LastError back to zero. this appears to be an undocumented
348         behavior in Windows, in doesn't cost much to match it */
349         SetLastError(0);
350         goto done;
351     }
352
353     if(numberOfBytes == 0)
354     {
355         // PAL's realloc behaves like free for a requested size of zero bytes. Force a nonzero size to get a valid pointer.
356         numberOfBytes = 1;
357     }
358
359 #ifdef __APPLE__
360     // This is patterned off of InternalRealloc in malloc.cpp.
361     {
362         pMem = (BYTE *) malloc_zone_realloc((malloc_zone_t *)hHeap, lpmem, numberOfBytes);
363     }
364 #else // __APPLE__
365     pMem = (BYTE *) PAL_realloc(lpmem, numberOfBytes);
366 #endif // __APPLE__ else
367
368     if (pMem == NULL)
369     {
370         ERROR("Not enough memory\n");
371         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
372         goto done;
373     }
374
375 done:
376     LOGEXIT("HeapReAlloc returns LPVOID %p\n", pMem);
377     PERF_EXIT(HeapReAlloc);
378     return pMem;
379 }
380
381 BOOL
382 PALAPI
383 HeapSetInformation(
384         IN OPTIONAL HANDLE HeapHandle,
385         IN HEAP_INFORMATION_CLASS HeapInformationClass,
386         IN PVOID HeapInformation,
387         IN SIZE_T HeapInformationLength)
388 {
389     return TRUE;
390 }