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 | HeapCreate |
67 | |
68 | See MSDN doc. |
69 | --*/ |
70 | HANDLE |
71 | PALAPI |
72 | HeapCreate( |
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 | /*++ |
113 | Function: |
114 | GetProcessHeap |
115 | |
116 | See MSDN doc. |
117 | --*/ |
118 | HANDLE |
119 | PALAPI |
120 | GetProcessHeap( |
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 | /*++ |
145 | Function: |
146 | HeapAlloc |
147 | |
148 | Abstract |
149 | Implemented as wrapper over malloc |
150 | |
151 | See MSDN doc. |
152 | --*/ |
153 | LPVOID |
154 | PALAPI |
155 | HeapAlloc( |
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 | /*++ |
219 | Function: |
220 | HeapFree |
221 | |
222 | Abstract |
223 | Implemented as wrapper over free |
224 | |
225 | See MSDN doc. |
226 | --*/ |
227 | BOOL |
228 | PALAPI |
229 | HeapFree( |
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 | |
273 | done: |
274 | LOGEXIT( "HeapFree returning BOOL %d\n" , bRetVal ); |
275 | PERF_EXIT(HeapFree); |
276 | return bRetVal; |
277 | } |
278 | |
279 | |
280 | /*++ |
281 | Function: |
282 | HeapReAlloc |
283 | |
284 | Abstract |
285 | Implemented as wrapper over realloc |
286 | |
287 | See MSDN doc. |
288 | --*/ |
289 | LPVOID |
290 | PALAPI |
291 | HeapReAlloc( |
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 | |
352 | done: |
353 | LOGEXIT("HeapReAlloc returns LPVOID %p\n" , pMem); |
354 | PERF_EXIT(HeapReAlloc); |
355 | return pMem; |
356 | } |
357 | |
358 | BOOL |
359 | PALAPI |
360 | HeapSetInformation( |
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 | |