Made header file usage more consistent
[reactos.git] / reactos / lib / ntdll / rtl / heap.c
1 /*
2 * Win32 heap functions
3 *
4 * Copyright 1996 Alexandre Julliard
5 * Copyright 1998 Ulrich Weigand
6 */
7
8 #include <string.h>
9 #include <ddk/ntddk.h>
10 #include <ntdll/rtl.h>
11 #include <ntos/heap.h>
12 #include <ntos/minmax.h>
13
14 #define NDEBUG
15 #include <ntdll/ntdll.h>
16
17 CRITICAL_SECTION ProcessHeapsLock;
18
19 /* Note: the heap data structures are based on what Pietrek describes in his
20 * book 'Windows 95 System Programming Secrets'. The layout is not exactly
21 * the same, but could be easily adapted if it turns out some programs
22 * require it.
23 */
24
25 typedef struct tagARENA_INUSE
26 {
27 DWORD size; /* Block size; must be the first field */
28 WORD threadId; /* Allocating thread id */
29 WORD magic; /* Magic number */
30 DWORD callerEIP; /* EIP of caller upon allocation */
31 } ARENA_INUSE;
32
33 typedef struct tagARENA_FREE
34 {
35 DWORD size; /* Block size; must be the first field */
36 WORD threadId; /* Freeing thread id */
37 WORD magic; /* Magic number */
38 struct tagARENA_FREE *next; /* Next free arena */
39 struct tagARENA_FREE *prev; /* Prev free arena */
40 } ARENA_FREE;
41
42 #define ARENA_FLAG_FREE 0x00000001 /* flags OR'ed with arena size */
43 #define ARENA_FLAG_PREV_FREE 0x00000002
44 #define ARENA_SIZE_MASK 0xfffffffc
45 #define ARENA_INUSE_MAGIC 0x4842 /* Value for arena 'magic' field */
46 #define ARENA_FREE_MAGIC 0x4846 /* Value for arena 'magic' field */
47
48 #define ARENA_INUSE_FILLER 0x55
49 #define ARENA_FREE_FILLER 0xaa
50
51 #define HEAP_NB_FREE_LISTS 4 /* Number of free lists */
52
53 /* Max size of the blocks on the free lists */
54 static const DWORD HEAP_freeListSizes[HEAP_NB_FREE_LISTS] =
55 {
56 0x20, 0x80, 0x200, 0xffffffff
57 };
58
59 typedef struct
60 {
61 DWORD size;
62 ARENA_FREE arena;
63 } FREE_LIST_ENTRY;
64
65 struct tagHEAP;
66
67 typedef struct tagSUBHEAP
68 {
69 DWORD size; /* Size of the whole sub-heap */
70 DWORD commitSize; /* Committed size of the sub-heap */
71 DWORD headerSize; /* Size of the heap header */
72 struct tagSUBHEAP *next; /* Next sub-heap */
73 struct tagHEAP *heap; /* Main heap structure */
74 DWORD magic; /* Magic number */
75 WORD selector; /* Selector for HEAP_WINE_SEGPTR heaps */
76 } SUBHEAP;
77
78 #define SUBHEAP_MAGIC ((DWORD)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24)))
79
80 typedef struct tagHEAP
81 {
82 SUBHEAP subheap; /* First sub-heap */
83 struct tagHEAP *next; /* Next heap for this process */
84 FREE_LIST_ENTRY freeList[HEAP_NB_FREE_LISTS]; /* Free lists */
85 CRITICAL_SECTION critSection; /* Critical section for serialization */
86 DWORD flags; /* Heap flags */
87 DWORD magic; /* Magic number */
88 } HEAP;
89
90 #define HEAP_MAGIC ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
91
92 #define HEAP_DEF_SIZE 0x110000 /* Default heap size = 1Mb + 64Kb */
93 #define HEAP_MIN_BLOCK_SIZE (8+sizeof(ARENA_FREE)) /* Min. heap block size */
94
95
96 /***********************************************************************
97 * HEAP_Dump
98 */
99 void HEAP_Dump( HEAP *heap )
100 {
101 int i;
102 SUBHEAP *subheap;
103 char *ptr;
104
105 DPRINT( "Heap: %08lx\n", (DWORD)heap );
106 DPRINT( "Next: %08lx Sub-heaps: %08lx",
107 (DWORD)heap->next, (DWORD)&heap->subheap );
108 subheap = &heap->subheap;
109 while (subheap->next)
110 {
111 DPRINT( " -> %08lx", (DWORD)subheap->next );
112 subheap = subheap->next;
113 }
114
115 DPRINT( "\nFree lists:\n Block Stat Size Id\n" );
116 for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
117 DPRINT( "%08lx free %08lx %04x prev=%08lx next=%08lx\n",
118 (DWORD)&heap->freeList[i].arena, heap->freeList[i].arena.size,
119 heap->freeList[i].arena.threadId,
120 (DWORD)heap->freeList[i].arena.prev,
121 (DWORD)heap->freeList[i].arena.next );
122
123 subheap = &heap->subheap;
124 while (subheap)
125 {
126 DWORD freeSize = 0, usedSize = 0, arenaSize = subheap->headerSize;
127 DPRINT( "\n\nSub-heap %08lx: size=%08lx committed=%08lx\n",
128 (DWORD)subheap, subheap->size, subheap->commitSize );
129
130 DPRINT( "\n Block Stat Size Id\n" );
131 ptr = (char*)subheap + subheap->headerSize;
132 while (ptr < (char *)subheap + subheap->size)
133 {
134 if (*(DWORD *)ptr & ARENA_FLAG_FREE)
135 {
136 ARENA_FREE *pArena = (ARENA_FREE *)ptr;
137 DPRINT( "%08lx free %08lx %04x prev=%08lx next=%08lx\n",
138 (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
139 pArena->threadId, (DWORD)pArena->prev,
140 (DWORD)pArena->next);
141 ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
142 arenaSize += sizeof(ARENA_FREE);
143 freeSize += pArena->size & ARENA_SIZE_MASK;
144 }
145 else if (*(DWORD *)ptr & ARENA_FLAG_PREV_FREE)
146 {
147 ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
148 DPRINT( "%08lx Used %08lx %04x back=%08lx EIP=%08lx\n",
149 (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
150 pArena->threadId, *((DWORD *)pArena - 1),
151 pArena->callerEIP );
152 ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
153 arenaSize += sizeof(ARENA_INUSE);
154 usedSize += pArena->size & ARENA_SIZE_MASK;
155 }
156 else
157 {
158 ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
159 DPRINT( "%08lx used %08lx %04x EIP=%08lx\n",
160 (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
161 pArena->threadId, pArena->callerEIP );
162 ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
163 arenaSize += sizeof(ARENA_INUSE);
164 usedSize += pArena->size & ARENA_SIZE_MASK;
165 }
166 }
167 DPRINT( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n",
168 subheap->size, subheap->commitSize, freeSize, usedSize,
169 arenaSize, (arenaSize * 100) / subheap->size );
170 subheap = subheap->next;
171 }
172 }
173
174
175 /***********************************************************************
176 * HEAP_GetPtr
177 * RETURNS
178 * Pointer to the heap
179 * NULL: Failure
180 */
181 static HEAP *HEAP_GetPtr(
182 HANDLE heap /* [in] Handle to the heap */
183 ) {
184 HEAP *heapPtr = (HEAP *)heap;
185 if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
186 {
187 DPRINT(heap, "Invalid heap %08x!\n", heap );
188 // SetLastError( ERROR_INVALID_HANDLE );
189 return NULL;
190 }
191 if (!RtlValidateHeap( heap, 0, NULL ))
192 {
193 HEAP_Dump( heapPtr );
194 DPRINT("NTDLL:%s:%d: assertion failed\n",__FILE__,__LINE__);
195 // SetLastError( ERROR_INVALID_HANDLE );
196 return NULL;
197 }
198 return heapPtr;
199 }
200
201
202 /***********************************************************************
203 * HEAP_InsertFreeBlock
204 *
205 * Insert a free block into the free list.
206 */
207 static void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena )
208 {
209 FREE_LIST_ENTRY *pEntry = heap->freeList;
210 while (pEntry->size < pArena->size) pEntry++;
211 pArena->size |= ARENA_FLAG_FREE;
212 pArena->next = pEntry->arena.next;
213 pArena->next->prev = pArena;
214 pArena->prev = &pEntry->arena;
215 pEntry->arena.next = pArena;
216 }
217
218
219 /***********************************************************************
220 * HEAP_FindSubHeap
221 * Find the sub-heap containing a given address.
222 *
223 * RETURNS
224 * Pointer: Success
225 * NULL: Failure
226 */
227 static SUBHEAP *HEAP_FindSubHeap(
228 HEAP *heap, /* [in] Heap pointer */
229 LPCVOID ptr /* [in] Address */
230 ) {
231 SUBHEAP *sub = &heap->subheap;
232 while (sub)
233 {
234 if (((char *)ptr >= (char *)sub) &&
235 ((char *)ptr < (char *)sub + sub->size)) return sub;
236 sub = sub->next;
237 }
238 return NULL;
239 }
240
241
242 /***********************************************************************
243 * HEAP_Commit
244 *
245 * Make sure the heap storage is committed up to (not including) ptr.
246 */
247 static BOOL HEAP_Commit( SUBHEAP *subheap, void *ptr )
248 {
249 DWORD size = (DWORD)((char *)ptr - (char *)subheap);
250 ULONG commitsize;
251 PVOID address;
252 NTSTATUS Status;
253
254 size = (size + 0xfff) & 0xfffff000; /* Align size on a page boundary */
255 if (size > subheap->size) size = subheap->size;
256 if (size <= subheap->commitSize) return TRUE;
257 commitsize = size - subheap->commitSize;
258 address = (PVOID)((char *)subheap + subheap->commitSize);
259 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
260 &address,
261 0,
262 &commitsize,
263 MEM_COMMIT,
264 PAGE_EXECUTE_READWRITE);
265 if (!NT_SUCCESS(Status))
266 {
267 DPRINT("ZwAllocateVirtualMemory failed\n");
268 return(FALSE);
269 }
270 subheap->commitSize = size;
271 return TRUE;
272 }
273
274
275 /***********************************************************************
276 * HEAP_Decommit
277 *
278 * If possible, decommit the heap storage from (including) 'ptr'.
279 */
280 static BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr )
281 {
282 DWORD size = (DWORD)((char *)ptr - (char *)subheap);
283 PVOID freebase;
284 ULONG freesize;
285 NTSTATUS Status;
286
287 size = (size + 0xfff) & 0xfffff000; /* Align size on a page boundary */
288 if (size >= subheap->commitSize) return TRUE;
289 freebase = (PVOID)((char *)subheap + size);
290 freesize = subheap->commitSize - size;
291 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
292 &freebase,
293 &freesize,
294 MEM_DECOMMIT);
295 if (!NT_SUCCESS(Status))
296 {
297 DPRINT("Could not decommit %08lx bytes at %08lx for heap %08lx\n",
298 subheap->commitSize - size,
299 (DWORD)((char *)subheap + size),
300 (DWORD)subheap->heap );
301 return FALSE;
302 }
303 subheap->commitSize = size;
304 return TRUE;
305 }
306
307
308 /***********************************************************************
309 * HEAP_CreateFreeBlock
310 *
311 * Create a free block at a specified address. 'size' is the size of the
312 * whole block, including the new arena.
313 */
314 static void HEAP_CreateFreeBlock( SUBHEAP *subheap, void *ptr, DWORD size )
315 {
316 ARENA_FREE *pFree;
317
318 /* Create a free arena */
319
320 pFree = (ARENA_FREE *)ptr;
321 pFree->magic = ARENA_FREE_MAGIC;
322
323 /* If debugging, erase the freed block content */
324
325 if (1) // DEBUGGING
326 {
327 char *pEnd = (char *)ptr + size;
328 if (pEnd > (char *)subheap + subheap->commitSize)
329 pEnd = (char *)subheap + subheap->commitSize;
330 if (pEnd > (char *)(pFree + 1))
331 memset( pFree + 1, ARENA_FREE_FILLER, pEnd - (char *)(pFree + 1) );
332 }
333
334 /* Check if next block is free also */
335
336 if (((char *)ptr + size < (char *)subheap + subheap->size) &&
337 (*(DWORD *)((char *)ptr + size) & ARENA_FLAG_FREE))
338 {
339 /* Remove the next arena from the free list */
340 ARENA_FREE *pNext = (ARENA_FREE *)((char *)ptr + size);
341 pNext->next->prev = pNext->prev;
342 pNext->prev->next = pNext->next;
343 size += (pNext->size & ARENA_SIZE_MASK) + sizeof(*pNext);
344 if (1) // DEBUGGING
345 memset( pNext, ARENA_FREE_FILLER, sizeof(ARENA_FREE) );
346 }
347
348 /* Set the next block PREV_FREE flag and pointer */
349
350 if ((char *)ptr + size < (char *)subheap + subheap->size)
351 {
352 DWORD *pNext = (DWORD *)((char *)ptr + size);
353 *pNext |= ARENA_FLAG_PREV_FREE;
354 *(ARENA_FREE **)(pNext - 1) = pFree;
355 }
356
357 /* Last, insert the new block into the free list */
358
359 pFree->size = size - sizeof(*pFree);
360 HEAP_InsertFreeBlock( subheap->heap, pFree );
361 }
362
363
364 /***********************************************************************
365 * HEAP_MakeInUseBlockFree
366 *
367 * Turn an in-use block into a free block. Can also decommit the end of
368 * the heap, and possibly even free the sub-heap altogether.
369 */
370 static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena )
371 {
372 ARENA_FREE *pFree;
373 DWORD size = (pArena->size & ARENA_SIZE_MASK) + sizeof(*pArena);
374
375 /* Check if we can merge with previous block */
376
377 if (pArena->size & ARENA_FLAG_PREV_FREE)
378 {
379 pFree = *((ARENA_FREE **)pArena - 1);
380 size += (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
381 /* Remove it from the free list */
382 pFree->next->prev = pFree->prev;
383 pFree->prev->next = pFree->next;
384 }
385 else pFree = (ARENA_FREE *)pArena;
386
387 /* Create a free block */
388
389 HEAP_CreateFreeBlock( subheap, pFree, size );
390 size = (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
391 if ((char *)pFree + size < (char *)subheap + subheap->size)
392 return; /* Not the last block, so nothing more to do */
393
394 /* Free the whole sub-heap if it's empty and not the original one */
395
396 if (((char *)pFree == (char *)subheap + subheap->headerSize) &&
397 (subheap != &subheap->heap->subheap))
398 {
399 SUBHEAP *pPrev = &subheap->heap->subheap;
400 /* Remove the free block from the list */
401 pFree->next->prev = pFree->prev;
402 pFree->prev->next = pFree->next;
403 /* Remove the subheap from the list */
404 while (pPrev && (pPrev->next != subheap)) pPrev = pPrev->next;
405 if (pPrev) pPrev->next = subheap->next;
406 /* Free the memory */
407 subheap->magic = 0;
408 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID*)&subheap, 0, MEM_RELEASE );
409 return;
410 }
411
412 /* Decommit the end of the heap */
413
414 HEAP_Decommit( subheap, pFree + 1 );
415 }
416
417
418 /***********************************************************************
419 * HEAP_ShrinkBlock
420 *
421 * Shrink an in-use block.
422 */
423 static void HEAP_ShrinkBlock(SUBHEAP *subheap, ARENA_INUSE *pArena, DWORD size)
424 {
425 if ((pArena->size & ARENA_SIZE_MASK) >= size + HEAP_MIN_BLOCK_SIZE)
426 {
427 HEAP_CreateFreeBlock( subheap, (char *)(pArena + 1) + size,
428 (pArena->size & ARENA_SIZE_MASK) - size );
429 pArena->size = (pArena->size & ~ARENA_SIZE_MASK) | size;
430 }
431 else
432 {
433 /* Turn off PREV_FREE flag in next block */
434 char *pNext = (char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK);
435 if (pNext < (char *)subheap + subheap->size)
436 *(DWORD *)pNext &= ~ARENA_FLAG_PREV_FREE;
437 }
438 }
439
440 /***********************************************************************
441 * HEAP_InitSubHeap
442 */
443 static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags,
444 DWORD commitSize, DWORD totalSize )
445 {
446 SUBHEAP *subheap = (SUBHEAP *)address;
447 FREE_LIST_ENTRY *pEntry;
448 int i;
449 NTSTATUS Status;
450
451 /* Commit memory */
452
453 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
454 &address,
455 0,
456 (PULONG)&commitSize,
457 MEM_COMMIT,
458 PAGE_EXECUTE_READWRITE);
459 if (!NT_SUCCESS(Status))
460 {
461 DPRINT("Could not commit %08lx bytes for sub-heap %08lx\n",
462 commitSize, (DWORD)address );
463 return FALSE;
464 }
465
466
467 /* Fill the sub-heap structure */
468
469 subheap->heap = heap;
470 subheap->size = totalSize;
471 subheap->commitSize = commitSize;
472 subheap->magic = SUBHEAP_MAGIC;
473
474 if ( subheap != (SUBHEAP *)heap )
475 {
476 /* If this is a secondary subheap, insert it into list */
477
478 subheap->headerSize = sizeof(SUBHEAP);
479 subheap->next = heap->subheap.next;
480 heap->subheap.next = subheap;
481 }
482 else
483 {
484 /* If this is a primary subheap, initialize main heap */
485
486 subheap->headerSize = sizeof(HEAP);
487 subheap->next = NULL;
488 heap->next = NULL;
489 heap->flags = flags;
490 heap->magic = HEAP_MAGIC;
491
492 /* Build the free lists */
493
494 for (i = 0, pEntry = heap->freeList; i < HEAP_NB_FREE_LISTS; i++, pEntry++)
495 {
496 pEntry->size = HEAP_freeListSizes[i];
497 pEntry->arena.size = 0 | ARENA_FLAG_FREE;
498 pEntry->arena.next = i < HEAP_NB_FREE_LISTS-1 ?
499 &heap->freeList[i+1].arena : &heap->freeList[0].arena;
500 pEntry->arena.prev = i ? &heap->freeList[i-1].arena :
501 &heap->freeList[HEAP_NB_FREE_LISTS-1].arena;
502 pEntry->arena.threadId = 0;
503 pEntry->arena.magic = ARENA_FREE_MAGIC;
504 }
505
506 /* Initialize critical section */
507
508 RtlInitializeCriticalSection( &heap->critSection );
509 }
510
511 /* Create the first free block */
512
513 HEAP_CreateFreeBlock( subheap, (LPBYTE)subheap + subheap->headerSize,
514 subheap->size - subheap->headerSize );
515
516 return TRUE;
517 }
518
519 /***********************************************************************
520 * HEAP_CreateSubHeap
521 *
522 * Create a sub-heap of the given size.
523 * If heap == NULL, creates a main heap.
524 */
525 static SUBHEAP *HEAP_CreateSubHeap(PVOID BaseAddress,
526 HEAP *heap,
527 DWORD flags,
528 DWORD commitSize,
529 DWORD totalSize )
530 {
531 LPVOID address;
532
533 /* Round-up sizes on a 64K boundary */
534
535 totalSize = (totalSize + 0xffff) & 0xffff0000;
536 commitSize = (commitSize + 0xffff) & 0xffff0000;
537 if (!commitSize) commitSize = 0x10000;
538 if (totalSize < commitSize) totalSize = commitSize;
539
540 /* Allocate the memory block */
541
542 address = BaseAddress;
543 ZwAllocateVirtualMemory(NtCurrentProcess(),
544 &address,
545 0,
546 (PULONG)&totalSize,
547 MEM_RESERVE,
548 PAGE_EXECUTE_READWRITE);
549
550 /* Initialize subheap */
551
552 if (!HEAP_InitSubHeap( heap? heap : (HEAP *)address,
553 address, flags, commitSize, totalSize ))
554 {
555 ZwFreeVirtualMemory(NtCurrentProcess(), address, 0, MEM_RELEASE );
556 return NULL;
557 }
558
559 return (SUBHEAP *)address;
560 }
561
562
563 /***********************************************************************
564 * HEAP_FindFreeBlock
565 *
566 * Find a free block at least as large as the requested size, and make sure
567 * the requested size is committed.
568 */
569 static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, DWORD size,
570 SUBHEAP **ppSubHeap )
571 {
572 SUBHEAP *subheap;
573 ARENA_FREE *pArena;
574 FREE_LIST_ENTRY *pEntry = heap->freeList;
575
576 /* Find a suitable free list, and in it find a block large enough */
577
578 while (pEntry->size < size) pEntry++;
579 pArena = pEntry->arena.next;
580 while (pArena != &heap->freeList[0].arena)
581 {
582 if (pArena->size > size)
583 {
584 subheap = HEAP_FindSubHeap( heap, pArena );
585 if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
586 + size + HEAP_MIN_BLOCK_SIZE))
587 return NULL;
588 *ppSubHeap = subheap;
589 return pArena;
590 }
591
592 pArena = pArena->next;
593 }
594
595 /* If no block was found, attempt to grow the heap */
596
597 if (!(heap->flags & HEAP_GROWABLE))
598 {
599 DPRINT("Not enough space in heap %08lx for %08lx bytes\n",
600 (DWORD)heap, size );
601 return NULL;
602 }
603 size += sizeof(SUBHEAP) + sizeof(ARENA_FREE);
604 if (!(subheap = HEAP_CreateSubHeap( NULL, heap, heap->flags, size,
605 max( HEAP_DEF_SIZE, size ) )))
606 return NULL;
607
608 DPRINT("created new sub-heap %08lx of %08lx bytes for heap %08lx\n",
609 (DWORD)subheap, size, (DWORD)heap );
610
611 *ppSubHeap = subheap;
612 return (ARENA_FREE *)(subheap + 1);
613 }
614
615
616 /***********************************************************************
617 * HEAP_IsValidArenaPtr
618 *
619 * Check that the pointer is inside the range possible for arenas.
620 */
621 static BOOL HEAP_IsValidArenaPtr( HEAP *heap, void *ptr )
622 {
623 int i;
624 SUBHEAP *subheap = HEAP_FindSubHeap( heap, ptr );
625 if (!subheap) return FALSE;
626 if ((char *)ptr >= (char *)subheap + subheap->headerSize) return TRUE;
627 if (subheap != &heap->subheap) return FALSE;
628 for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
629 if (ptr == (void *)&heap->freeList[i].arena) return TRUE;
630 return FALSE;
631 }
632
633
634 /***********************************************************************
635 * HEAP_ValidateFreeArena
636 */
637 static BOOL HEAP_ValidateFreeArena( SUBHEAP *subheap, ARENA_FREE *pArena )
638 {
639 char *heapEnd = (char *)subheap + subheap->size;
640
641 /* Check magic number */
642 if (pArena->magic != ARENA_FREE_MAGIC)
643 {
644 DPRINT("Heap %08lx: invalid free arena magic for %08lx\n",
645 (DWORD)subheap->heap, (DWORD)pArena );
646 return FALSE;
647 }
648 /* Check size flags */
649 if (!(pArena->size & ARENA_FLAG_FREE) ||
650 (pArena->size & ARENA_FLAG_PREV_FREE))
651 {
652 DPRINT("Heap %08lx: bad flags %lx for free arena %08lx\n",
653 (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
654 }
655 /* Check arena size */
656 if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
657 {
658 DPRINT("Heap %08lx: bad size %08lx for free arena %08lx\n",
659 (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
660 return FALSE;
661 }
662 /* Check that next pointer is valid */
663 if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->next ))
664 {
665 DPRINT("Heap %08lx: bad next ptr %08lx for arena %08lx\n",
666 (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
667 return FALSE;
668 }
669 /* Check that next arena is free */
670 if (!(pArena->next->size & ARENA_FLAG_FREE) ||
671 (pArena->next->magic != ARENA_FREE_MAGIC))
672 {
673 DPRINT("Heap %08lx: next arena %08lx invalid for %08lx\n",
674 (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
675 return FALSE;
676 }
677 /* Check that prev pointer is valid */
678 if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->prev ))
679 {
680 DPRINT("Heap %08lx: bad prev ptr %08lx for arena %08lx\n",
681 (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
682 return FALSE;
683 }
684 /* Check that prev arena is free */
685 if (!(pArena->prev->size & ARENA_FLAG_FREE) ||
686 (pArena->prev->magic != ARENA_FREE_MAGIC))
687 {
688 DPRINT("Heap %08lx: prev arena %08lx invalid for %08lx\n",
689 (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
690 return FALSE;
691 }
692 /* Check that next block has PREV_FREE flag */
693 if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd)
694 {
695 if (!(*(DWORD *)((char *)(pArena + 1) +
696 (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
697 {
698 DPRINT("Heap %08lx: free arena %08lx next block has no PREV_FREE flag\n",
699 (DWORD)subheap->heap, (DWORD)pArena );
700 return FALSE;
701 }
702 /* Check next block back pointer */
703 if (*((ARENA_FREE **)((char *)(pArena + 1) +
704 (pArena->size & ARENA_SIZE_MASK)) - 1) != pArena)
705 {
706 DPRINT("Heap %08lx: arena %08lx has wrong back ptr %08lx\n",
707 (DWORD)subheap->heap, (DWORD)pArena,
708 *((DWORD *)((char *)(pArena+1)+ (pArena->size & ARENA_SIZE_MASK)) - 1));
709 return FALSE;
710 }
711 }
712 return TRUE;
713 }
714
715
716 /***********************************************************************
717 * HEAP_ValidateInUseArena
718 */
719 static BOOL HEAP_ValidateInUseArena( SUBHEAP *subheap, ARENA_INUSE *pArena )
720 {
721 char *heapEnd = (char *)subheap + subheap->size;
722
723 /* Check magic number */
724 if (pArena->magic != ARENA_INUSE_MAGIC)
725 {
726 DPRINT("Heap %08lx: invalid in-use arena magic for %08lx\n",
727 (DWORD)subheap->heap, (DWORD)pArena );
728 return FALSE;
729 }
730 /* Check size flags */
731 if (pArena->size & ARENA_FLAG_FREE)
732 {
733 DPRINT("Heap %08lx: bad flags %lx for in-use arena %08lx\n",
734 (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
735 }
736 /* Check arena size */
737 if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
738 {
739 DPRINT("Heap %08lx: bad size %08lx for in-use arena %08lx\n",
740 (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
741 return FALSE;
742 }
743 /* Check next arena PREV_FREE flag */
744 if (((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd) &&
745 (*(DWORD *)((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
746 {
747 DPRINT("Heap %08lx: in-use arena %08lx next block has PREV_FREE flag\n",
748 (DWORD)subheap->heap, (DWORD)pArena );
749 return FALSE;
750 }
751 /* Check prev free arena */
752 if (pArena->size & ARENA_FLAG_PREV_FREE)
753 {
754 ARENA_FREE *pPrev = *((ARENA_FREE **)pArena - 1);
755 /* Check prev pointer */
756 if (!HEAP_IsValidArenaPtr( subheap->heap, pPrev ))
757 {
758 DPRINT("Heap %08lx: bad back ptr %08lx for arena %08lx\n",
759 (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
760 return FALSE;
761 }
762 /* Check that prev arena is free */
763 if (!(pPrev->size & ARENA_FLAG_FREE) ||
764 (pPrev->magic != ARENA_FREE_MAGIC))
765 {
766 DPRINT("Heap %08lx: prev arena %08lx invalid for in-use %08lx\n",
767 (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
768 return FALSE;
769 }
770 /* Check that prev arena is really the previous block */
771 if ((char *)(pPrev + 1) + (pPrev->size & ARENA_SIZE_MASK) != (char *)pArena)
772 {
773 DPRINT("Heap %08lx: prev arena %08lx is not prev for in-use %08lx\n",
774 (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
775 return FALSE;
776 }
777 }
778 return TRUE;
779 }
780
781
782 /***********************************************************************
783 * HEAP_IsInsideHeap
784 * Checks whether the pointer points to a block inside a given heap.
785 *
786 * NOTES
787 * Should this return BOOL32?
788 *
789 * RETURNS
790 * !0: Success
791 * 0: Failure
792 */
793 int HEAP_IsInsideHeap(
794 HANDLE heap, /* [in] Heap */
795 DWORD flags, /* [in] Flags */
796 LPCVOID ptr /* [in] Pointer */
797 ) {
798 HEAP *heapPtr = HEAP_GetPtr( heap );
799 SUBHEAP *subheap;
800 int ret;
801
802 /* Validate the parameters */
803
804 if (!heapPtr) return 0;
805 flags |= heapPtr->flags;
806 if (!(flags & HEAP_NO_SERIALIZE)) RtlLockHeap( heap );
807 ret = (((subheap = HEAP_FindSubHeap( heapPtr, ptr )) != NULL) &&
808 (((char *)ptr >= (char *)subheap + subheap->headerSize
809 + sizeof(ARENA_INUSE))));
810 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
811 return ret;
812 }
813
814
815 /***********************************************************************
816 * HeapCreate (KERNEL32.336)
817 * RETURNS
818 * Handle of heap: Success
819 * NULL: Failure
820 */
821 HANDLE STDCALL RtlCreateHeap(ULONG flags,
822 PVOID BaseAddress,
823 ULONG initialSize,
824 ULONG maxSize,
825 PVOID Unknown,
826 PRTL_HEAP_DEFINITION Definition)
827 {
828 SUBHEAP *subheap;
829
830 /* Allocate the heap block */
831
832 DPRINT("RtlCreateHeap(flags %x, BaseAddress %x, initialSize %x, "
833 "maxSize %x\n)",flags,BaseAddress,initialSize, maxSize);
834
835 if (!maxSize)
836 {
837 maxSize = HEAP_DEF_SIZE;
838 flags |= HEAP_GROWABLE;
839 }
840 if (!(subheap = HEAP_CreateSubHeap(BaseAddress,
841 NULL,
842 flags,
843 initialSize,
844 maxSize)))
845 {
846 // SetLastError( ERROR_OUTOFMEMORY );
847 DPRINT("RtlCreateHeap() = %x\n",0);
848 return 0;
849 }
850
851 DPRINT("RtlCreateHeap() = %x\n",subheap);
852
853 return (HANDLE)subheap;
854 }
855
856 /***********************************************************************
857 * HeapDestroy (KERNEL32.337)
858 * RETURNS
859 * TRUE: Success
860 * FALSE: Failure
861 */
862 BOOL STDCALL RtlDestroyHeap(
863 HANDLE heap /* [in] Handle of heap */
864 ) {
865 HEAP *heapPtr = HEAP_GetPtr( heap );
866 SUBHEAP *subheap;
867
868 DPRINT("%08x\n", heap );
869 if (!heapPtr) return FALSE;
870
871 RtlDeleteCriticalSection( &heapPtr->critSection );
872 subheap = &heapPtr->subheap;
873 while (subheap)
874 {
875 SUBHEAP *next = subheap->next;
876 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID*)&subheap, 0, MEM_RELEASE );
877 subheap = next;
878 }
879 return TRUE;
880 }
881
882
883 /***********************************************************************
884 * HeapAlloc (KERNEL32.334)
885 * RETURNS
886 * Pointer to allocated memory block
887 * NULL: Failure
888 */
889 PVOID STDCALL RtlAllocateHeap(
890 HANDLE heap, /* [in] Handle of private heap block */
891 ULONG flags, /* [in] Heap allocation control flags */
892 ULONG size /* [in] Number of bytes to allocate */
893 ) {
894 ARENA_FREE *pArena;
895 ARENA_INUSE *pInUse;
896 SUBHEAP *subheap;
897 HEAP *heapPtr = HEAP_GetPtr( heap );
898
899 /* Validate the parameters */
900
901 if (!heapPtr) return NULL;
902 flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY;
903 flags |= heapPtr->flags;
904 if (!(flags & HEAP_NO_SERIALIZE)) RtlLockHeap( heap );
905 size = (size + 3) & ~3;
906 if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
907
908 /* Locate a suitable free block */
909
910 if (!(pArena = HEAP_FindFreeBlock( heapPtr, size, &subheap )))
911 {
912 DPRINT("(%08x,%08lx,%08lx): returning NULL\n",
913 heap, flags, size );
914 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
915 // SetLastError( ERROR_COMMITMENT_LIMIT );
916 return NULL;
917 }
918
919 /* Remove the arena from the free list */
920
921 pArena->next->prev = pArena->prev;
922 pArena->prev->next = pArena->next;
923
924 /* Build the in-use arena */
925
926 pInUse = (ARENA_INUSE *)pArena;
927 pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE)
928 + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
929 pInUse->callerEIP = *((DWORD *)&heap - 1); /* hack hack */
930 // pInUse->threadId = GetCurrentTask();
931 pInUse->magic = ARENA_INUSE_MAGIC;
932
933 /* Shrink the block */
934
935 HEAP_ShrinkBlock( subheap, pInUse, size );
936
937 if (flags & HEAP_ZERO_MEMORY) memset( pInUse + 1, 0, size );
938 else if (1) memset( pInUse + 1, ARENA_INUSE_FILLER, size ); //DEBUGGING
939
940 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
941
942 DPRINT("(%08x,%08lx,%08lx): returning %08lx\n",
943 heap, flags, size, (DWORD)(pInUse + 1) );
944 return (LPVOID)(pInUse + 1);
945 }
946
947
948 /***********************************************************************
949 * HeapFree (KERNEL32.338)
950 * RETURNS
951 * TRUE: Success
952 * FALSE: Failure
953 */
954 BOOLEAN STDCALL RtlFreeHeap(
955 HANDLE heap, /* [in] Handle of heap */
956 ULONG flags, /* [in] Heap freeing flags */
957 PVOID ptr /* [in] Address of memory to free */
958 ) {
959 ARENA_INUSE *pInUse;
960 SUBHEAP *subheap;
961 HEAP *heapPtr = HEAP_GetPtr( heap );
962
963 /* Validate the parameters */
964
965 if (!heapPtr) return FALSE;
966 flags &= HEAP_NO_SERIALIZE;
967 flags |= heapPtr->flags;
968 if (!(flags & HEAP_NO_SERIALIZE)) RtlLockHeap( heap );
969 if (!ptr)
970 {
971 DPRINT("(%08x,%08lx,%08lx): asked to free NULL\n",
972 heap, flags, (DWORD)ptr );
973 }
974 if (!ptr || !RtlValidateHeap( heap, HEAP_NO_SERIALIZE, ptr ))
975 {
976 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
977 // SetLastError( ERROR_INVALID_PARAMETER );
978 DPRINT("(%08x,%08lx,%08lx): returning FALSE\n",
979 heap, flags, (DWORD)ptr );
980 return FALSE;
981 }
982
983 /* Turn the block into a free block */
984
985 pInUse = (ARENA_INUSE *)ptr - 1;
986 subheap = HEAP_FindSubHeap( heapPtr, pInUse );
987 HEAP_MakeInUseBlockFree( subheap, pInUse );
988
989 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
990 /* SetLastError( 0 ); */
991
992 DPRINT("(%08x,%08lx,%08lx): returning TRUE\n",
993 heap, flags, (DWORD)ptr );
994 return TRUE;
995 }
996
997
998 /***********************************************************************
999 * HeapReAlloc (KERNEL32.340)
1000 * RETURNS
1001 * Pointer to reallocated memory block
1002 * NULL: Failure
1003 *
1004 * REVISIONS
1005 * Renamed RtlReAllocateHeap as in NT
1006 */
1007 LPVOID
1008 STDCALL
1009 RtlReAllocateHeap (
1010 HANDLE heap, /* [in] Handle of heap block */
1011 DWORD flags, /* [in] Heap reallocation flags */
1012 LPVOID ptr, /* [in] Address of memory to reallocate */
1013 DWORD size /* [in] Number of bytes to reallocate */
1014 )
1015 {
1016 ARENA_INUSE *pArena;
1017 DWORD oldSize;
1018 HEAP *heapPtr;
1019 SUBHEAP *subheap;
1020
1021 if (!ptr) return RtlAllocateHeap( heap, flags, size ); /* FIXME: correct? */
1022 if (!(heapPtr = HEAP_GetPtr( heap ))) return FALSE;
1023
1024 /* Validate the parameters */
1025
1026 flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY |
1027 HEAP_REALLOC_IN_PLACE_ONLY;
1028 flags |= heapPtr->flags;
1029 size = (size + 3) & ~3;
1030 if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
1031
1032 if (!(flags & HEAP_NO_SERIALIZE)) RtlLockHeap( heap );
1033 if (!RtlValidateHeap( heap, HEAP_NO_SERIALIZE, ptr ))
1034 {
1035 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
1036 // SetLastError( ERROR_INVALID_PARAMETER );
1037 DPRINT("(%08x,%08lx,%08lx,%08lx): returning NULL\n",
1038 heap, flags, (DWORD)ptr, size );
1039 return NULL;
1040 }
1041
1042 /* Check if we need to grow the block */
1043
1044 pArena = (ARENA_INUSE *)ptr - 1;
1045 // pArena->threadId = GetCurrentTask();
1046 subheap = HEAP_FindSubHeap( heapPtr, pArena );
1047 oldSize = (pArena->size & ARENA_SIZE_MASK);
1048 if (size > oldSize)
1049 {
1050 char *pNext = (char *)(pArena + 1) + oldSize;
1051 if ((pNext < (char *)subheap + subheap->size) &&
1052 (*(DWORD *)pNext & ARENA_FLAG_FREE) &&
1053 (oldSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= size))
1054 {
1055 /* The next block is free and large enough */
1056 ARENA_FREE *pFree = (ARENA_FREE *)pNext;
1057 pFree->next->prev = pFree->prev;
1058 pFree->prev->next = pFree->next;
1059 pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree);
1060 if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
1061 + size + HEAP_MIN_BLOCK_SIZE))
1062 {
1063 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
1064 // SetLastError( ERROR_OUTOFMEMORY );
1065 return NULL;
1066 }
1067 HEAP_ShrinkBlock( subheap, pArena, size );
1068 }
1069 else /* Do it the hard way */
1070 {
1071 ARENA_FREE *pNew;
1072 ARENA_INUSE *pInUse;
1073 SUBHEAP *newsubheap;
1074
1075 if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) ||
1076 !(pNew = HEAP_FindFreeBlock( heapPtr, size, &newsubheap )))
1077 {
1078 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
1079 // SetLastError( ERROR_OUTOFMEMORY );
1080 return NULL;
1081 }
1082
1083 /* Build the in-use arena */
1084
1085 pNew->next->prev = pNew->prev;
1086 pNew->prev->next = pNew->next;
1087 pInUse = (ARENA_INUSE *)pNew;
1088 pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE)
1089 + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
1090 // pInUse->threadId = GetCurrentTask();
1091 pInUse->magic = ARENA_INUSE_MAGIC;
1092 HEAP_ShrinkBlock( newsubheap, pInUse, size );
1093 memcpy( pInUse + 1, pArena + 1, oldSize );
1094
1095 /* Free the previous block */
1096
1097 HEAP_MakeInUseBlockFree( subheap, pArena );
1098 subheap = newsubheap;
1099 pArena = pInUse;
1100 }
1101 }
1102 else HEAP_ShrinkBlock( subheap, pArena, size ); /* Shrink the block */
1103
1104 /* Clear the extra bytes if needed */
1105
1106 if (size > oldSize)
1107 {
1108 if (flags & HEAP_ZERO_MEMORY)
1109 memset( (char *)(pArena + 1) + oldSize, 0,
1110 (pArena->size & ARENA_SIZE_MASK) - oldSize );
1111 else if (1) // DEBUGGING
1112 memset( (char *)(pArena + 1) + oldSize, ARENA_INUSE_FILLER,
1113 (pArena->size & ARENA_SIZE_MASK) - oldSize );
1114 }
1115
1116 /* Return the new arena */
1117
1118 pArena->callerEIP = *((DWORD *)&heap - 1); /* hack hack */
1119 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
1120
1121 DPRINT("(%08x,%08lx,%08lx,%08lx): returning %08lx\n",
1122 heap, flags, (DWORD)ptr, size, (DWORD)(pArena + 1) );
1123 return (LPVOID)(pArena + 1);
1124 }
1125
1126
1127 /***********************************************************************
1128 * HeapCompact (KERNEL32.335)
1129 */
1130 DWORD STDCALL RtlCompactHeap( HANDLE heap, DWORD flags )
1131 {
1132 return 0;
1133 }
1134
1135
1136 /***********************************************************************
1137 * HeapLock (KERNEL32.339)
1138 * Attempts to acquire the critical section object for a specified heap.
1139 *
1140 * RETURNS
1141 * TRUE: Success
1142 * FALSE: Failure
1143 */
1144 BOOL STDCALL RtlLockHeap(
1145 HANDLE heap /* [in] Handle of heap to lock for exclusive access */
1146 ) {
1147 HEAP *heapPtr = HEAP_GetPtr( heap );
1148 if (!heapPtr) return FALSE;
1149 RtlEnterCriticalSection( &heapPtr->critSection );
1150 return TRUE;
1151 }
1152
1153
1154 /***********************************************************************
1155 * HeapUnlock (KERNEL32.342)
1156 * Releases ownership of the critical section object.
1157 *
1158 * RETURNS
1159 * TRUE: Success
1160 * FALSE: Failure
1161 */
1162 BOOL STDCALL RtlUnlockHeap(
1163 HANDLE heap /* [in] Handle to the heap to unlock */
1164 ) {
1165 HEAP *heapPtr = HEAP_GetPtr( heap );
1166 if (!heapPtr) return FALSE;
1167 RtlLeaveCriticalSection( &heapPtr->critSection );
1168 return TRUE;
1169 }
1170
1171
1172 /***********************************************************************
1173 * HeapSize (KERNEL32.341)
1174 * RETURNS
1175 * Size in bytes of allocated memory
1176 * 0: Failure
1177 */
1178 DWORD STDCALL RtlSizeHeap(
1179 HANDLE heap, /* [in] Handle of heap */
1180 DWORD flags, /* [in] Heap size control flags */
1181 LPVOID ptr /* [in] Address of memory to return size for */
1182 ) {
1183 DWORD ret;
1184 HEAP *heapPtr = HEAP_GetPtr( heap );
1185
1186 if (!heapPtr) return FALSE;
1187 flags &= HEAP_NO_SERIALIZE;
1188 flags |= heapPtr->flags;
1189 if (!(flags & HEAP_NO_SERIALIZE)) RtlLockHeap( heap );
1190 if (!RtlValidateHeap( heap, HEAP_NO_SERIALIZE, ptr ))
1191 {
1192 // SetLastError( ERROR_INVALID_PARAMETER );
1193 ret = 0xffffffff;
1194 }
1195 else
1196 {
1197 ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1;
1198 ret = pArena->size & ARENA_SIZE_MASK;
1199 }
1200 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
1201
1202 DPRINT("(%08x,%08lx,%08lx): returning %08lx\n",
1203 heap, flags, (DWORD)ptr, ret );
1204 return ret;
1205 }
1206
1207
1208 /***********************************************************************
1209 * HeapValidate (KERNEL32.343)
1210 * Validates a specified heap.
1211 *
1212 * NOTES
1213 * Flags is ignored.
1214 *
1215 * RETURNS
1216 * TRUE: Success
1217 * FALSE: Failure
1218 */
1219 BOOL STDCALL RtlValidateHeap(
1220 HANDLE heap, /* [in] Handle to the heap */
1221 DWORD flags, /* [in] Bit flags that control access during operation */
1222 PVOID block /* [in] Optional pointer to memory block to validate */
1223 ) {
1224 SUBHEAP *subheap;
1225 HEAP *heapPtr = (HEAP *)(heap);
1226
1227 if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
1228 {
1229 DPRINT("Invalid heap %08x!\n", heap );
1230 return FALSE;
1231 }
1232
1233 if (block)
1234 {
1235 /* Only check this single memory block */
1236 if (!(subheap = HEAP_FindSubHeap( heapPtr, block )) ||
1237 ((char *)block < (char *)subheap + subheap->headerSize
1238 + sizeof(ARENA_INUSE)))
1239 {
1240 DPRINT("Heap %08lx: block %08lx is not inside heap\n",
1241 (DWORD)heap, (DWORD)block );
1242 return FALSE;
1243 }
1244 return HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)block - 1 );
1245 }
1246
1247 subheap = &heapPtr->subheap;
1248 while (subheap)
1249 {
1250 char *ptr = (char *)subheap + subheap->headerSize;
1251 while (ptr < (char *)subheap + subheap->size)
1252 {
1253 if (*(DWORD *)ptr & ARENA_FLAG_FREE)
1254 {
1255 if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr ))
1256 return FALSE;
1257 ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
1258 }
1259 else
1260 {
1261 if (!HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)ptr ))
1262 return FALSE;
1263 ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
1264 }
1265 }
1266 subheap = subheap->next;
1267 }
1268 return TRUE;
1269 }
1270
1271 HANDLE STDCALL RtlGetProcessHeap(VOID)
1272 {
1273 DPRINT("RtlGetProcessHeap()\n");
1274 return (HANDLE)NtCurrentPeb()->ProcessHeap;
1275 }
1276
1277 VOID
1278 RtlpInitProcessHeaps (PPEB Peb)
1279 {
1280 Peb->NumberOfHeaps = 0;
1281 Peb->MaximumNumberOfHeaps = (PAGESIZE - sizeof(PPEB)) / sizeof(HANDLE);
1282 Peb->ProcessHeaps = (PVOID)Peb + sizeof(PEB);
1283
1284 RtlInitializeCriticalSection (&ProcessHeapsLock);
1285 }
1286
1287
1288 NTSTATUS
1289 STDCALL
1290 RtlEnumProcessHeaps (
1291 DWORD STDCALL(*func)(void*,LONG),
1292 LONG lParam
1293 )
1294 {
1295 NTSTATUS Status = STATUS_SUCCESS;
1296 ULONG i;
1297
1298 RtlEnterCriticalSection (&ProcessHeapsLock);
1299
1300 for (i = 0; i < NtCurrentPeb ()->NumberOfHeaps; i++)
1301 {
1302 Status = func (NtCurrentPeb ()->ProcessHeaps[i],lParam);
1303 if(!NT_SUCCESS(Status))
1304 break;
1305 }
1306
1307 RtlLeaveCriticalSection (&ProcessHeapsLock);
1308
1309 return Status;
1310 }
1311
1312
1313 ULONG
1314 STDCALL
1315 RtlGetProcessHeaps (
1316 ULONG HeapCount,
1317 HANDLE *HeapArray
1318 )
1319 {
1320 ULONG Result = 0;
1321
1322 RtlEnterCriticalSection (&ProcessHeapsLock);
1323
1324 if (NtCurrentPeb ()->NumberOfHeaps <= HeapCount)
1325 {
1326 Result = NtCurrentPeb ()->NumberOfHeaps;
1327 memmove (HeapArray,
1328 NtCurrentPeb ()->ProcessHeaps,
1329 Result * sizeof(HANDLE));
1330 }
1331
1332 RtlLeaveCriticalSection (&ProcessHeapsLock);
1333
1334 return Result;
1335 }
1336
1337
1338 BOOLEAN
1339 STDCALL
1340 RtlValidateProcessHeaps (
1341 VOID
1342 )
1343 {
1344 HANDLE Heaps[128];
1345 BOOLEAN Result = TRUE;
1346 ULONG HeapCount;
1347 ULONG i;
1348
1349 HeapCount = RtlGetProcessHeaps (128, Heaps);
1350 for (i = 0; i < HeapCount; i++)
1351 {
1352 if (!RtlValidateHeap (Heaps[i], 0, NULL))
1353 Result = FALSE;
1354 }
1355
1356 return Result;
1357 }
1358
1359 /* EOF */