Improved FormatMessage:
[wine] / memory / heap.c
1 /*
2  * Win32 heap functions
3  *
4  * Copyright 1996 Alexandre Julliard
5  * Copyright 1998 Ulrich Weigand
6  */
7
8 #include <assert.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include "wine/winbase16.h"
13 #include "wine/winestring.h"
14 #include "selectors.h"
15 #include "global.h"
16 #include "winbase.h"
17 #include "winerror.h"
18 #include "winnt.h"
19 #include "heap.h"
20 #include "toolhelp.h"
21 #include "debugtools.h"
22 #include "winnls.h"
23
24 DEFAULT_DEBUG_CHANNEL(heap);
25
26 /* Note: the heap data structures are based on what Pietrek describes in his
27  * book 'Windows 95 System Programming Secrets'. The layout is not exactly
28  * the same, but could be easily adapted if it turns out some programs
29  * require it.
30  */
31
32 typedef struct tagARENA_INUSE
33 {
34     DWORD  size;                    /* Block size; must be the first field */
35     WORD   threadId;                /* Allocating thread id */
36     WORD   magic;                   /* Magic number */
37     void  *callerEIP;               /* EIP of caller upon allocation */
38 } ARENA_INUSE;
39
40 typedef struct tagARENA_FREE
41 {
42     DWORD                 size;     /* Block size; must be the first field */
43     WORD                  threadId; /* Freeing thread id */
44     WORD                  magic;    /* Magic number */
45     struct tagARENA_FREE *next;     /* Next free arena */
46     struct tagARENA_FREE *prev;     /* Prev free arena */
47 } ARENA_FREE;
48
49 #define ARENA_FLAG_FREE        0x00000001  /* flags OR'ed with arena size */
50 #define ARENA_FLAG_PREV_FREE   0x00000002
51 #define ARENA_SIZE_MASK        0xfffffffc
52 #define ARENA_INUSE_MAGIC      0x4842      /* Value for arena 'magic' field */
53 #define ARENA_FREE_MAGIC       0x4846      /* Value for arena 'magic' field */
54
55 #define ARENA_INUSE_FILLER     0x55
56 #define ARENA_FREE_FILLER      0xaa
57
58 #define QUIET                  1           /* Suppress messages  */
59 #define NOISY                  0           /* Report all errors  */
60
61 #define HEAP_NB_FREE_LISTS   4   /* Number of free lists */
62
63 /* Max size of the blocks on the free lists */
64 static const DWORD HEAP_freeListSizes[HEAP_NB_FREE_LISTS] =
65 {
66     0x20, 0x80, 0x200, 0xffffffff
67 };
68
69 typedef struct
70 {
71     DWORD       size;
72     ARENA_FREE  arena;
73 } FREE_LIST_ENTRY;
74
75 struct tagHEAP;
76
77 typedef struct tagSUBHEAP
78 {
79     DWORD               size;       /* Size of the whole sub-heap */
80     DWORD               commitSize; /* Committed size of the sub-heap */
81     DWORD               headerSize; /* Size of the heap header */
82     struct tagSUBHEAP  *next;       /* Next sub-heap */
83     struct tagHEAP     *heap;       /* Main heap structure */
84     DWORD               magic;      /* Magic number */
85     WORD                selector;   /* Selector for HEAP_WINE_SEGPTR heaps */
86 } SUBHEAP;
87
88 #define SUBHEAP_MAGIC    ((DWORD)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24)))
89
90 typedef struct tagHEAP
91 {
92     SUBHEAP          subheap;       /* First sub-heap */
93     struct tagHEAP  *next;          /* Next heap for this process */
94     FREE_LIST_ENTRY  freeList[HEAP_NB_FREE_LISTS];  /* Free lists */
95     CRITICAL_SECTION critSection;   /* Critical section for serialization */
96     DWORD            flags;         /* Heap flags */
97     DWORD            magic;         /* Magic number */
98     void            *private;       /* Private pointer for the user of the heap */
99 } HEAP;
100
101 #define HEAP_MAGIC       ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
102
103 #define HEAP_DEF_SIZE        0x110000   /* Default heap size = 1Mb + 64Kb */
104 #define HEAP_MIN_BLOCK_SIZE  (8+sizeof(ARENA_FREE))  /* Min. heap block size */
105 #define COMMIT_MASK          0xffff  /* bitmask for commit/decommit granularity */
106
107 HANDLE SystemHeap = 0;
108 HANDLE SegptrHeap = 0;
109
110 SYSTEM_HEAP_DESCR *SystemHeapDescr = 0;
111
112 static HEAP *processHeap;  /* main process heap */
113 static HEAP *firstHeap;    /* head of secondary heaps list */
114
115 /* address where we try to map the system heap */
116 #define SYSTEM_HEAP_BASE  ((void*)0x65430000)
117
118 static BOOL HEAP_IsRealArena( HANDLE heap, DWORD flags, LPCVOID block, BOOL quiet );
119
120 #ifdef __GNUC__
121 #define GET_EIP()    (__builtin_return_address(0))
122 #define SET_EIP(ptr) ((ARENA_INUSE*)(ptr) - 1)->callerEIP = GET_EIP()
123 #else
124 #define GET_EIP()    0
125 #define SET_EIP(ptr) /* nothing */
126 #endif  /* __GNUC__ */
127
128 /***********************************************************************
129  *           HEAP_Dump
130  */
131 void HEAP_Dump( HEAP *heap )
132 {
133     int i;
134     SUBHEAP *subheap;
135     char *ptr;
136
137     DPRINTF( "Heap: %08lx\n", (DWORD)heap );
138     DPRINTF( "Next: %08lx  Sub-heaps: %08lx",
139           (DWORD)heap->next, (DWORD)&heap->subheap );
140     subheap = &heap->subheap;
141     while (subheap->next)
142     {
143         DPRINTF( " -> %08lx", (DWORD)subheap->next );
144         subheap = subheap->next;
145     }
146
147     DPRINTF( "\nFree lists:\n Block   Stat   Size    Id\n" );
148     for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
149         DPRINTF( "%08lx free %08lx %04x prev=%08lx next=%08lx\n",
150               (DWORD)&heap->freeList[i].arena, heap->freeList[i].arena.size,
151               heap->freeList[i].arena.threadId,
152               (DWORD)heap->freeList[i].arena.prev,
153               (DWORD)heap->freeList[i].arena.next );
154
155     subheap = &heap->subheap;
156     while (subheap)
157     {
158         DWORD freeSize = 0, usedSize = 0, arenaSize = subheap->headerSize;
159         DPRINTF( "\n\nSub-heap %08lx: size=%08lx committed=%08lx\n",
160               (DWORD)subheap, subheap->size, subheap->commitSize );
161         
162         DPRINTF( "\n Block   Stat   Size    Id\n" );
163         ptr = (char*)subheap + subheap->headerSize;
164         while (ptr < (char *)subheap + subheap->size)
165         {
166             if (*(DWORD *)ptr & ARENA_FLAG_FREE)
167             {
168                 ARENA_FREE *pArena = (ARENA_FREE *)ptr;
169                 DPRINTF( "%08lx free %08lx %04x prev=%08lx next=%08lx\n",
170                       (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
171                       pArena->threadId, (DWORD)pArena->prev,
172                       (DWORD)pArena->next);
173                 ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
174                 arenaSize += sizeof(ARENA_FREE);
175                 freeSize += pArena->size & ARENA_SIZE_MASK;
176             }
177             else if (*(DWORD *)ptr & ARENA_FLAG_PREV_FREE)
178             {
179                 ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
180                 DPRINTF( "%08lx Used %08lx %04x back=%08lx EIP=%p\n",
181                       (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
182                       pArena->threadId, *((DWORD *)pArena - 1),
183                       pArena->callerEIP );
184                 ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
185                 arenaSize += sizeof(ARENA_INUSE);
186                 usedSize += pArena->size & ARENA_SIZE_MASK;
187             }
188             else
189             {
190                 ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
191                 DPRINTF( "%08lx used %08lx %04x EIP=%p\n",
192                       (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
193                       pArena->threadId, pArena->callerEIP );
194                 ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
195                 arenaSize += sizeof(ARENA_INUSE);
196                 usedSize += pArena->size & ARENA_SIZE_MASK;
197             }
198         }
199         DPRINTF( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n",
200               subheap->size, subheap->commitSize, freeSize, usedSize,
201               arenaSize, (arenaSize * 100) / subheap->size );
202         subheap = subheap->next;
203     }
204 }
205
206
207 /***********************************************************************
208  *           HEAP_GetPtr
209  * RETURNS
210  *      Pointer to the heap
211  *      NULL: Failure
212  */
213 static HEAP *HEAP_GetPtr(
214              HANDLE heap /* [in] Handle to the heap */
215 ) {
216     HEAP *heapPtr = (HEAP *)heap;
217     if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
218     {
219         ERR("Invalid heap %08x!\n", heap );
220         SetLastError( ERROR_INVALID_HANDLE );
221         return NULL;
222     }
223     if (TRACE_ON(heap) && !HEAP_IsRealArena( heap, 0, NULL, NOISY ))
224     {
225         HEAP_Dump( heapPtr );
226         assert( FALSE );
227         SetLastError( ERROR_INVALID_HANDLE );
228         return NULL;
229     }
230     return heapPtr;
231 }
232
233
234 /***********************************************************************
235  *           HEAP_InsertFreeBlock
236  *
237  * Insert a free block into the free list.
238  */
239 static void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena )
240 {
241     FREE_LIST_ENTRY *pEntry = heap->freeList;
242     while (pEntry->size < pArena->size) pEntry++;
243     pArena->size      |= ARENA_FLAG_FREE;
244     pArena->next       = pEntry->arena.next;
245     pArena->next->prev = pArena;
246     pArena->prev       = &pEntry->arena;
247     pEntry->arena.next = pArena;
248 }
249
250
251 /***********************************************************************
252  *           HEAP_FindSubHeap
253  * Find the sub-heap containing a given address.
254  *
255  * RETURNS
256  *      Pointer: Success
257  *      NULL: Failure
258  */
259 static SUBHEAP *HEAP_FindSubHeap(
260                 HEAP *heap, /* [in] Heap pointer */
261                 LPCVOID ptr /* [in] Address */
262 ) {
263     SUBHEAP *sub = &heap->subheap;
264     while (sub)
265     {
266         if (((char *)ptr >= (char *)sub) &&
267             ((char *)ptr < (char *)sub + sub->size)) return sub;
268         sub = sub->next;
269     }
270     return NULL;
271 }
272
273
274 /***********************************************************************
275  *           HEAP_Commit
276  *
277  * Make sure the heap storage is committed up to (not including) ptr.
278  */
279 static inline BOOL HEAP_Commit( SUBHEAP *subheap, void *ptr )
280 {
281     DWORD size = (DWORD)((char *)ptr - (char *)subheap);
282     size = (size + COMMIT_MASK) & ~COMMIT_MASK;
283     if (size > subheap->size) size = subheap->size;
284     if (size <= subheap->commitSize) return TRUE;
285     if (!VirtualAlloc( (char *)subheap + subheap->commitSize,
286                        size - subheap->commitSize, MEM_COMMIT,
287                        PAGE_EXECUTE_READWRITE))
288     {
289         WARN("Could not commit %08lx bytes at %08lx for heap %08lx\n",
290                  size - subheap->commitSize,
291                  (DWORD)((char *)subheap + subheap->commitSize),
292                  (DWORD)subheap->heap );
293         return FALSE;
294     }
295     subheap->commitSize = size;
296     return TRUE;
297 }
298
299
300 /***********************************************************************
301  *           HEAP_Decommit
302  *
303  * If possible, decommit the heap storage from (including) 'ptr'.
304  */
305 static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr )
306 {
307     DWORD size = (DWORD)((char *)ptr - (char *)subheap);
308     /* round to next block and add one full block */
309     size = ((size + COMMIT_MASK) & ~COMMIT_MASK) + COMMIT_MASK + 1;
310     if (size >= subheap->commitSize) return TRUE;
311     if (!VirtualFree( (char *)subheap + size,
312                       subheap->commitSize - size, MEM_DECOMMIT ))
313     {
314         WARN("Could not decommit %08lx bytes at %08lx for heap %08lx\n",
315                  subheap->commitSize - size,
316                  (DWORD)((char *)subheap + size),
317                  (DWORD)subheap->heap );
318         return FALSE;
319     }
320     subheap->commitSize = size;
321     return TRUE;
322 }
323
324
325 /***********************************************************************
326  *           HEAP_CreateFreeBlock
327  *
328  * Create a free block at a specified address. 'size' is the size of the
329  * whole block, including the new arena.
330  */
331 static void HEAP_CreateFreeBlock( SUBHEAP *subheap, void *ptr, DWORD size )
332 {
333     ARENA_FREE *pFree;
334
335     /* Create a free arena */
336
337     pFree = (ARENA_FREE *)ptr;
338     pFree->threadId = GetCurrentTask();
339     pFree->magic = ARENA_FREE_MAGIC;
340
341     /* If debugging, erase the freed block content */
342
343     if (TRACE_ON(heap))
344     {
345         char *pEnd = (char *)ptr + size;
346         if (pEnd > (char *)subheap + subheap->commitSize)
347             pEnd = (char *)subheap + subheap->commitSize;
348         if (pEnd > (char *)(pFree + 1))
349             memset( pFree + 1, ARENA_FREE_FILLER, pEnd - (char *)(pFree + 1) );
350     }
351
352     /* Check if next block is free also */
353
354     if (((char *)ptr + size < (char *)subheap + subheap->size) &&
355         (*(DWORD *)((char *)ptr + size) & ARENA_FLAG_FREE))
356     {
357         /* Remove the next arena from the free list */
358         ARENA_FREE *pNext = (ARENA_FREE *)((char *)ptr + size);
359         pNext->next->prev = pNext->prev;
360         pNext->prev->next = pNext->next;
361         size += (pNext->size & ARENA_SIZE_MASK) + sizeof(*pNext);
362         if (TRACE_ON(heap))
363             memset( pNext, ARENA_FREE_FILLER, sizeof(ARENA_FREE) );
364     }
365
366     /* Set the next block PREV_FREE flag and pointer */
367
368     if ((char *)ptr + size < (char *)subheap + subheap->size)
369     {
370         DWORD *pNext = (DWORD *)((char *)ptr + size);
371         *pNext |= ARENA_FLAG_PREV_FREE;
372         *(ARENA_FREE **)(pNext - 1) = pFree;
373     }
374
375     /* Last, insert the new block into the free list */
376
377     pFree->size = size - sizeof(*pFree);
378     HEAP_InsertFreeBlock( subheap->heap, pFree );
379 }
380
381
382 /***********************************************************************
383  *           HEAP_MakeInUseBlockFree
384  *
385  * Turn an in-use block into a free block. Can also decommit the end of
386  * the heap, and possibly even free the sub-heap altogether.
387  */
388 static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena )
389 {
390     ARENA_FREE *pFree;
391     DWORD size = (pArena->size & ARENA_SIZE_MASK) + sizeof(*pArena);
392
393     /* Check if we can merge with previous block */
394
395     if (pArena->size & ARENA_FLAG_PREV_FREE)
396     {
397         pFree = *((ARENA_FREE **)pArena - 1);
398         size += (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
399         /* Remove it from the free list */
400         pFree->next->prev = pFree->prev;
401         pFree->prev->next = pFree->next;
402     }
403     else pFree = (ARENA_FREE *)pArena;
404
405     /* Create a free block */
406
407     HEAP_CreateFreeBlock( subheap, pFree, size );
408     size = (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
409     if ((char *)pFree + size < (char *)subheap + subheap->size)
410         return;  /* Not the last block, so nothing more to do */
411
412     /* Free the whole sub-heap if it's empty and not the original one */
413
414     if (((char *)pFree == (char *)subheap + subheap->headerSize) &&
415         (subheap != &subheap->heap->subheap))
416     {
417         SUBHEAP *pPrev = &subheap->heap->subheap;
418         /* Remove the free block from the list */
419         pFree->next->prev = pFree->prev;
420         pFree->prev->next = pFree->next;
421         /* Remove the subheap from the list */
422         while (pPrev && (pPrev->next != subheap)) pPrev = pPrev->next;
423         if (pPrev) pPrev->next = subheap->next;
424         /* Free the memory */
425         subheap->magic = 0;
426         if (subheap->selector) FreeSelector16( subheap->selector );
427         VirtualFree( subheap, 0, MEM_RELEASE );
428         return;
429     }
430     
431     /* Decommit the end of the heap */
432
433     if (!(subheap->heap->flags & HEAP_WINE_SHARED)) HEAP_Decommit( subheap, pFree + 1 );
434 }
435
436
437 /***********************************************************************
438  *           HEAP_ShrinkBlock
439  *
440  * Shrink an in-use block.
441  */
442 static void HEAP_ShrinkBlock(SUBHEAP *subheap, ARENA_INUSE *pArena, DWORD size)
443 {
444     if ((pArena->size & ARENA_SIZE_MASK) >= size + HEAP_MIN_BLOCK_SIZE)
445     {
446         HEAP_CreateFreeBlock( subheap, (char *)(pArena + 1) + size,
447                               (pArena->size & ARENA_SIZE_MASK) - size );
448         pArena->size = (pArena->size & ~ARENA_SIZE_MASK) | size;
449     }
450     else
451     {
452         /* Turn off PREV_FREE flag in next block */
453         char *pNext = (char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK);
454         if (pNext < (char *)subheap + subheap->size)
455             *(DWORD *)pNext &= ~ARENA_FLAG_PREV_FREE;
456     }
457 }
458
459 /***********************************************************************
460  *           HEAP_InitSubHeap
461  */
462 static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags,
463                                 DWORD commitSize, DWORD totalSize )
464 {
465     SUBHEAP *subheap = (SUBHEAP *)address;
466     WORD selector = 0;
467     FREE_LIST_ENTRY *pEntry;
468     int i;
469
470     /* Commit memory */
471
472     if (flags & HEAP_WINE_SHARED)
473         commitSize = totalSize;  /* always commit everything in a shared heap */
474     if (!VirtualAlloc(address, commitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
475     {
476         WARN("Could not commit %08lx bytes for sub-heap %08lx\n",
477                    commitSize, (DWORD)address );
478         return FALSE;
479     }
480
481     /* Allocate a selector if needed */
482
483     if (flags & HEAP_WINE_SEGPTR)
484     {
485         selector = SELECTOR_AllocBlock( address, totalSize,
486                            (flags & (HEAP_WINE_CODESEG|HEAP_WINE_CODE16SEG))
487                             ? SEGMENT_CODE : SEGMENT_DATA,
488                            (flags & HEAP_WINE_CODESEG) != 0, FALSE );
489         if (!selector)
490         {
491             ERR("Could not allocate selector\n" );
492             return FALSE;
493         }
494     }
495
496     /* Fill the sub-heap structure */
497
498     subheap->heap       = heap;
499     subheap->selector   = selector;
500     subheap->size       = totalSize;
501     subheap->commitSize = commitSize;
502     subheap->magic      = SUBHEAP_MAGIC;
503
504     if ( subheap != (SUBHEAP *)heap )
505     {
506         /* If this is a secondary subheap, insert it into list */
507
508         subheap->headerSize = sizeof(SUBHEAP);
509         subheap->next       = heap->subheap.next;
510         heap->subheap.next  = subheap;
511     }
512     else
513     {
514         /* If this is a primary subheap, initialize main heap */
515
516         subheap->headerSize = sizeof(HEAP);
517         subheap->next       = NULL;
518         heap->next          = NULL;
519         heap->flags         = flags;
520         heap->magic         = HEAP_MAGIC;
521
522         /* Build the free lists */
523
524         for (i = 0, pEntry = heap->freeList; i < HEAP_NB_FREE_LISTS; i++, pEntry++)
525         {
526             pEntry->size           = HEAP_freeListSizes[i];
527             pEntry->arena.size     = 0 | ARENA_FLAG_FREE;
528             pEntry->arena.next     = i < HEAP_NB_FREE_LISTS-1 ?
529                          &heap->freeList[i+1].arena : &heap->freeList[0].arena;
530             pEntry->arena.prev     = i ? &heap->freeList[i-1].arena : 
531                                    &heap->freeList[HEAP_NB_FREE_LISTS-1].arena;
532             pEntry->arena.threadId = 0;
533             pEntry->arena.magic    = ARENA_FREE_MAGIC;
534         }
535
536         /* Initialize critical section */
537
538         InitializeCriticalSection( &heap->critSection );
539         if (!SystemHeap) MakeCriticalSectionGlobal( &heap->critSection );
540     }
541  
542     /* Create the first free block */
543
544     HEAP_CreateFreeBlock( subheap, (LPBYTE)subheap + subheap->headerSize, 
545                           subheap->size - subheap->headerSize );
546
547     return TRUE;
548 }
549
550 /***********************************************************************
551  *           HEAP_CreateSubHeap
552  *
553  * Create a sub-heap of the given size.
554  * If heap == NULL, creates a main heap.
555  */
556 static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, DWORD flags, 
557                                     DWORD commitSize, DWORD totalSize )
558 {
559     LPVOID address;
560
561     /* Round-up sizes on a 64K boundary */
562
563     if (flags & HEAP_WINE_SEGPTR)
564     {
565         totalSize = commitSize = 0x10000;  /* Only 64K at a time for SEGPTRs */
566     }
567     else
568     {
569         totalSize  = (totalSize + 0xffff) & 0xffff0000;
570         commitSize = (commitSize + 0xffff) & 0xffff0000;
571         if (!commitSize) commitSize = 0x10000;
572         if (totalSize < commitSize) totalSize = commitSize;
573     }
574
575     /* Allocate the memory block */
576
577     if (!(address = VirtualAlloc( NULL, totalSize,
578                                   MEM_RESERVE, PAGE_EXECUTE_READWRITE )))
579     {
580         WARN("Could not VirtualAlloc %08lx bytes\n",
581                  totalSize );
582         return NULL;
583     }
584
585     /* Initialize subheap */
586
587     if (!HEAP_InitSubHeap( heap? heap : (HEAP *)address, 
588                            address, flags, commitSize, totalSize ))
589     {
590         VirtualFree( address, 0, MEM_RELEASE );
591         return NULL;
592     }
593
594     return (SUBHEAP *)address;
595 }
596
597
598 /***********************************************************************
599  *           HEAP_FindFreeBlock
600  *
601  * Find a free block at least as large as the requested size, and make sure
602  * the requested size is committed.
603  */
604 static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, DWORD size,
605                                        SUBHEAP **ppSubHeap )
606 {
607     SUBHEAP *subheap;
608     ARENA_FREE *pArena;
609     FREE_LIST_ENTRY *pEntry = heap->freeList;
610
611     /* Find a suitable free list, and in it find a block large enough */
612
613     while (pEntry->size < size) pEntry++;
614     pArena = pEntry->arena.next;
615     while (pArena != &heap->freeList[0].arena)
616     {
617         if (pArena->size > size)
618         {
619             subheap = HEAP_FindSubHeap( heap, pArena );
620             if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
621                                                + size + HEAP_MIN_BLOCK_SIZE))
622                 return NULL;
623             *ppSubHeap = subheap;
624             return pArena;
625         }
626
627         pArena = pArena->next;
628     }
629
630     /* If no block was found, attempt to grow the heap */
631
632     if (!(heap->flags & HEAP_GROWABLE))
633     {
634         WARN("Not enough space in heap %08lx for %08lx bytes\n",
635                  (DWORD)heap, size );
636         return NULL;
637     }
638     size += sizeof(SUBHEAP) + sizeof(ARENA_FREE);
639     if (!(subheap = HEAP_CreateSubHeap( heap, heap->flags, size,
640                                         max( HEAP_DEF_SIZE, size ) )))
641         return NULL;
642
643     TRACE("created new sub-heap %08lx of %08lx bytes for heap %08lx\n",
644                 (DWORD)subheap, size, (DWORD)heap );
645
646     *ppSubHeap = subheap;
647     return (ARENA_FREE *)(subheap + 1);
648 }
649
650
651 /***********************************************************************
652  *           HEAP_IsValidArenaPtr
653  *
654  * Check that the pointer is inside the range possible for arenas.
655  */
656 static BOOL HEAP_IsValidArenaPtr( HEAP *heap, void *ptr )
657 {
658     int i;
659     SUBHEAP *subheap = HEAP_FindSubHeap( heap, ptr );
660     if (!subheap) return FALSE;
661     if ((char *)ptr >= (char *)subheap + subheap->headerSize) return TRUE;
662     if (subheap != &heap->subheap) return FALSE;
663     for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
664         if (ptr == (void *)&heap->freeList[i].arena) return TRUE;
665     return FALSE;
666 }
667
668
669 /***********************************************************************
670  *           HEAP_ValidateFreeArena
671  */
672 static BOOL HEAP_ValidateFreeArena( SUBHEAP *subheap, ARENA_FREE *pArena )
673 {
674     char *heapEnd = (char *)subheap + subheap->size;
675
676     /* Check magic number */
677     if (pArena->magic != ARENA_FREE_MAGIC)
678     {
679         ERR("Heap %08lx: invalid free arena magic for %08lx\n",
680                  (DWORD)subheap->heap, (DWORD)pArena );
681         return FALSE;
682     }
683     /* Check size flags */
684     if (!(pArena->size & ARENA_FLAG_FREE) ||
685         (pArena->size & ARENA_FLAG_PREV_FREE))
686     {
687         ERR("Heap %08lx: bad flags %lx for free arena %08lx\n",
688                  (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
689     }
690     /* Check arena size */
691     if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
692     {
693         ERR("Heap %08lx: bad size %08lx for free arena %08lx\n",
694                  (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
695         return FALSE;
696     }
697     /* Check that next pointer is valid */
698     if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->next ))
699     {
700         ERR("Heap %08lx: bad next ptr %08lx for arena %08lx\n",
701                  (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
702         return FALSE;
703     }
704     /* Check that next arena is free */
705     if (!(pArena->next->size & ARENA_FLAG_FREE) ||
706         (pArena->next->magic != ARENA_FREE_MAGIC))
707     { 
708         ERR("Heap %08lx: next arena %08lx invalid for %08lx\n", 
709                  (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
710         return FALSE;
711     }
712     /* Check that prev pointer is valid */
713     if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->prev ))
714     {
715         ERR("Heap %08lx: bad prev ptr %08lx for arena %08lx\n",
716                  (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
717         return FALSE;
718     }
719     /* Check that prev arena is free */
720     if (!(pArena->prev->size & ARENA_FLAG_FREE) ||
721         (pArena->prev->magic != ARENA_FREE_MAGIC))
722     { 
723         ERR("Heap %08lx: prev arena %08lx invalid for %08lx\n", 
724                  (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
725         return FALSE;
726     }
727     /* Check that next block has PREV_FREE flag */
728     if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd)
729     {
730         if (!(*(DWORD *)((char *)(pArena + 1) +
731             (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
732         {
733             ERR("Heap %08lx: free arena %08lx next block has no PREV_FREE flag\n",
734                      (DWORD)subheap->heap, (DWORD)pArena );
735             return FALSE;
736         }
737         /* Check next block back pointer */
738         if (*((ARENA_FREE **)((char *)(pArena + 1) +
739             (pArena->size & ARENA_SIZE_MASK)) - 1) != pArena)
740         {
741             ERR("Heap %08lx: arena %08lx has wrong back ptr %08lx\n",
742                      (DWORD)subheap->heap, (DWORD)pArena,
743                      *((DWORD *)((char *)(pArena+1)+ (pArena->size & ARENA_SIZE_MASK)) - 1));
744             return FALSE;
745         }
746     }
747     return TRUE;
748 }
749
750
751 /***********************************************************************
752  *           HEAP_ValidateInUseArena
753  */
754 static BOOL HEAP_ValidateInUseArena( SUBHEAP *subheap, ARENA_INUSE *pArena, BOOL quiet )
755 {
756     char *heapEnd = (char *)subheap + subheap->size;
757
758     /* Check magic number */
759     if (pArena->magic != ARENA_INUSE_MAGIC)
760     {
761         if (quiet == NOISY) {
762         ERR("Heap %08lx: invalid in-use arena magic for %08lx\n",
763                  (DWORD)subheap->heap, (DWORD)pArena );
764             if (TRACE_ON(heap))
765                HEAP_Dump( subheap->heap );
766         }  else if (WARN_ON(heap)) {
767             WARN("Heap %08lx: invalid in-use arena magic for %08lx\n",
768                  (DWORD)subheap->heap, (DWORD)pArena );
769             if (TRACE_ON(heap))
770                HEAP_Dump( subheap->heap );
771         }
772         return FALSE;
773     }
774     /* Check size flags */
775     if (pArena->size & ARENA_FLAG_FREE) 
776     {
777         ERR("Heap %08lx: bad flags %lx for in-use arena %08lx\n",
778                  (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
779     }
780     /* Check arena size */
781     if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
782     {
783         ERR("Heap %08lx: bad size %08lx for in-use arena %08lx\n",
784                  (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
785         return FALSE;
786     }
787     /* Check next arena PREV_FREE flag */
788     if (((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd) &&
789         (*(DWORD *)((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
790     {
791         ERR("Heap %08lx: in-use arena %08lx next block has PREV_FREE flag\n",
792                  (DWORD)subheap->heap, (DWORD)pArena );
793         return FALSE;
794     }
795     /* Check prev free arena */
796     if (pArena->size & ARENA_FLAG_PREV_FREE)
797     {
798         ARENA_FREE *pPrev = *((ARENA_FREE **)pArena - 1);
799         /* Check prev pointer */
800         if (!HEAP_IsValidArenaPtr( subheap->heap, pPrev ))
801         {
802             ERR("Heap %08lx: bad back ptr %08lx for arena %08lx\n",
803                     (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
804             return FALSE;
805         }
806         /* Check that prev arena is free */
807         if (!(pPrev->size & ARENA_FLAG_FREE) ||
808             (pPrev->magic != ARENA_FREE_MAGIC))
809         { 
810             ERR("Heap %08lx: prev arena %08lx invalid for in-use %08lx\n", 
811                      (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
812             return FALSE;
813         }
814         /* Check that prev arena is really the previous block */
815         if ((char *)(pPrev + 1) + (pPrev->size & ARENA_SIZE_MASK) != (char *)pArena)
816         {
817             ERR("Heap %08lx: prev arena %08lx is not prev for in-use %08lx\n",
818                      (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
819             return FALSE;
820         }
821     }
822     return TRUE;
823 }
824
825
826 /***********************************************************************
827  *           HEAP_IsInsideHeap
828  * Checks whether the pointer points to a block inside a given heap.
829  *
830  * NOTES
831  *      Should this return BOOL32?
832  *
833  * RETURNS
834  *      !0: Success
835  *      0: Failure
836  */
837 int HEAP_IsInsideHeap(
838     HANDLE heap, /* [in] Heap */
839     DWORD flags,   /* [in] Flags */
840     LPCVOID ptr    /* [in] Pointer */
841 ) {
842     HEAP *heapPtr = HEAP_GetPtr( heap );
843     SUBHEAP *subheap;
844     int ret;
845
846     /* Validate the parameters */
847
848     if (!heapPtr) return 0;
849     flags |= heapPtr->flags;
850     if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
851     ret = (((subheap = HEAP_FindSubHeap( heapPtr, ptr )) != NULL) &&
852            (((char *)ptr >= (char *)subheap + subheap->headerSize
853                               + sizeof(ARENA_INUSE))));
854     if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
855     return ret;
856 }
857
858
859 /***********************************************************************
860  *           HEAP_GetSegptr
861  *
862  * Transform a linear pointer into a SEGPTR. The pointer must have been
863  * allocated from a HEAP_WINE_SEGPTR heap.
864  */
865 SEGPTR HEAP_GetSegptr( HANDLE heap, DWORD flags, LPCVOID ptr )
866 {
867     HEAP *heapPtr = HEAP_GetPtr( heap );
868     SUBHEAP *subheap;
869     SEGPTR ret;
870
871     /* Validate the parameters */
872
873     if (!heapPtr) return 0;
874     flags |= heapPtr->flags;
875     if (!(flags & HEAP_WINE_SEGPTR))
876     {
877         ERR("Heap %08x is not a SEGPTR heap\n",
878                  heap );
879         return 0;
880     }
881     if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
882
883     /* Get the subheap */
884
885     if (!(subheap = HEAP_FindSubHeap( heapPtr, ptr )))
886     {
887         ERR("%p is not inside heap %08x\n",
888                  ptr, heap );
889         if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
890         return 0;
891     }
892
893     /* Build the SEGPTR */
894
895     ret = PTR_SEG_OFF_TO_SEGPTR(subheap->selector, (DWORD)ptr-(DWORD)subheap);
896     if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
897     return ret;
898 }
899
900 /***********************************************************************
901  *           HEAP_IsRealArena  [Internal]
902  * Validates a block is a valid arena.
903  *
904  * RETURNS
905  *      TRUE: Success
906  *      FALSE: Failure
907  */
908 static BOOL HEAP_IsRealArena(
909               HANDLE heap,   /* [in] Handle to the heap */
910               DWORD flags,   /* [in] Bit flags that control access during operation */
911               LPCVOID block, /* [in] Optional pointer to memory block to validate */
912               BOOL quiet     /* [in] Flag - if true, HEAP_ValidateInUseArena
913                               *             does not complain    */
914 ) {
915     SUBHEAP *subheap;
916     HEAP *heapPtr = (HEAP *)(heap);
917     BOOL ret = TRUE;
918
919     if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
920     {
921         ERR("Invalid heap %08x!\n", heap );
922         return FALSE;
923     }
924
925     flags &= HEAP_NO_SERIALIZE;
926     flags |= heapPtr->flags;
927     /* calling HeapLock may result in infinite recursion, so do the critsect directly */
928     if (!(flags & HEAP_NO_SERIALIZE))
929         EnterCriticalSection( &heapPtr->critSection );
930
931     if (block)
932     {
933         /* Only check this single memory block */
934
935         /* The following code is really HEAP_IsInsideHeap   *
936          * with serialization already done.                 */
937         if (!(subheap = HEAP_FindSubHeap( heapPtr, block )) ||
938             ((char *)block < (char *)subheap + subheap->headerSize
939                               + sizeof(ARENA_INUSE)))
940         {
941             if (quiet == NOISY) 
942                 ERR("Heap %08lx: block %08lx is not inside heap\n",
943                      (DWORD)heap, (DWORD)block );
944             else if (WARN_ON(heap)) 
945                 WARN("Heap %08lx: block %08lx is not inside heap\n",
946                      (DWORD)heap, (DWORD)block );
947             ret = FALSE;
948         } else
949             ret = HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)block - 1, quiet );
950
951         if (!(flags & HEAP_NO_SERIALIZE))
952             LeaveCriticalSection( &heapPtr->critSection );
953         return ret;
954     }
955
956     subheap = &heapPtr->subheap;
957     while (subheap && ret)
958     {
959         char *ptr = (char *)subheap + subheap->headerSize;
960         while (ptr < (char *)subheap + subheap->size)
961         {
962             if (*(DWORD *)ptr & ARENA_FLAG_FREE)
963             {
964                 if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr )) {
965                     ret = FALSE;
966                     break;
967                 }
968                 ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
969             }
970             else
971             {
972                 if (!HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)ptr, NOISY )) {
973                     ret = FALSE;
974                     break;
975                 }
976                 ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
977             }
978         }
979         subheap = subheap->next;
980     }
981
982     if (!(flags & HEAP_NO_SERIALIZE))
983         LeaveCriticalSection( &heapPtr->critSection );
984     return ret;
985 }
986
987
988 /***********************************************************************
989  *           HeapCreate   (KERNEL32.336)
990  * RETURNS
991  *      Handle of heap: Success
992  *      NULL: Failure
993  */
994 HANDLE WINAPI HeapCreate(
995                 DWORD flags,       /* [in] Heap allocation flag */
996                 DWORD initialSize, /* [in] Initial heap size */
997                 DWORD maxSize      /* [in] Maximum heap size */
998 ) {
999     SUBHEAP *subheap;
1000
1001     /* Allocate the heap block */
1002
1003     if (!maxSize)
1004     {
1005         maxSize = HEAP_DEF_SIZE;
1006         flags |= HEAP_GROWABLE;
1007     }
1008     if (!(subheap = HEAP_CreateSubHeap( NULL, flags, initialSize, maxSize )))
1009     {
1010         SetLastError( ERROR_OUTOFMEMORY );
1011         return 0;
1012     }
1013
1014     /* link it into the per-process heap list */
1015     if (processHeap)
1016     {
1017         HEAP *heapPtr = subheap->heap;
1018         EnterCriticalSection( &processHeap->critSection );
1019         heapPtr->next = firstHeap;
1020         firstHeap = heapPtr;
1021         LeaveCriticalSection( &processHeap->critSection );
1022     }
1023     else  /* assume the first heap we create is the process main heap */
1024     {
1025         processHeap = subheap->heap;
1026     }
1027
1028     return (HANDLE)subheap;
1029 }
1030
1031 /***********************************************************************
1032  *           HeapDestroy   (KERNEL32.337)
1033  * RETURNS
1034  *      TRUE: Success
1035  *      FALSE: Failure
1036  */
1037 BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
1038 {
1039     HEAP *heapPtr = HEAP_GetPtr( heap );
1040     SUBHEAP *subheap;
1041
1042     TRACE("%08x\n", heap );
1043     if (!heapPtr) return FALSE;
1044
1045     if (heapPtr == processHeap)  /* cannot delete the main process heap */
1046     {
1047         SetLastError( ERROR_INVALID_PARAMETER );
1048         return FALSE;
1049     }
1050     else /* remove it from the per-process list */
1051     {
1052         HEAP **pptr;
1053         EnterCriticalSection( &processHeap->critSection );
1054         pptr = &firstHeap;
1055         while (*pptr && *pptr != heapPtr) pptr = &(*pptr)->next;
1056         if (*pptr) *pptr = (*pptr)->next;
1057         LeaveCriticalSection( &processHeap->critSection );
1058     }
1059
1060     DeleteCriticalSection( &heapPtr->critSection );
1061     subheap = &heapPtr->subheap;
1062     while (subheap)
1063     {
1064         SUBHEAP *next = subheap->next;
1065         if (subheap->selector) FreeSelector16( subheap->selector );
1066         VirtualFree( subheap, 0, MEM_RELEASE );
1067         subheap = next;
1068     }
1069     return TRUE;
1070 }
1071
1072
1073 /***********************************************************************
1074  *           HeapAlloc   (KERNEL32.334)
1075  * RETURNS
1076  *      Pointer to allocated memory block
1077  *      NULL: Failure
1078  */
1079 LPVOID WINAPI HeapAlloc(
1080               HANDLE heap, /* [in] Handle of private heap block */
1081               DWORD flags,   /* [in] Heap allocation control flags */
1082               DWORD size     /* [in] Number of bytes to allocate */
1083 ) {
1084     ARENA_FREE *pArena;
1085     ARENA_INUSE *pInUse;
1086     SUBHEAP *subheap;
1087     HEAP *heapPtr = HEAP_GetPtr( heap );
1088
1089     /* Validate the parameters */
1090
1091     if (!heapPtr) return NULL;
1092     flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY;
1093     flags |= heapPtr->flags;
1094     if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
1095     size = (size + 3) & ~3;
1096     if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
1097
1098     /* Locate a suitable free block */
1099
1100     if (!(pArena = HEAP_FindFreeBlock( heapPtr, size, &subheap )))
1101     {
1102         TRACE("(%08x,%08lx,%08lx): returning NULL\n",
1103                   heap, flags, size  );
1104         if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
1105         SetLastError( ERROR_COMMITMENT_LIMIT );
1106         return NULL;
1107     }
1108
1109     /* Remove the arena from the free list */
1110
1111     pArena->next->prev = pArena->prev;
1112     pArena->prev->next = pArena->next;
1113
1114     /* Build the in-use arena */
1115
1116     pInUse = (ARENA_INUSE *)pArena;
1117     pInUse->size      = (pInUse->size & ~ARENA_FLAG_FREE)
1118                         + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
1119     pInUse->callerEIP = GET_EIP();
1120     pInUse->threadId  = GetCurrentTask();
1121     pInUse->magic     = ARENA_INUSE_MAGIC;
1122
1123     /* Shrink the block */
1124
1125     HEAP_ShrinkBlock( subheap, pInUse, size );
1126
1127     if (flags & HEAP_ZERO_MEMORY)
1128         memset( pInUse + 1, 0, pInUse->size & ARENA_SIZE_MASK );
1129     else if (TRACE_ON(heap))
1130         memset( pInUse + 1, ARENA_INUSE_FILLER, pInUse->size & ARENA_SIZE_MASK );
1131
1132     if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
1133
1134     TRACE("(%08x,%08lx,%08lx): returning %08lx\n",
1135                   heap, flags, size, (DWORD)(pInUse + 1) );
1136     return (LPVOID)(pInUse + 1);
1137 }
1138
1139
1140 /***********************************************************************
1141  *           HeapFree   (KERNEL32.338)
1142  * RETURNS
1143  *      TRUE: Success
1144  *      FALSE: Failure
1145  */
1146 BOOL WINAPI HeapFree(
1147               HANDLE heap, /* [in] Handle of heap */
1148               DWORD flags,   /* [in] Heap freeing flags */
1149               LPVOID ptr     /* [in] Address of memory to free */
1150 ) {
1151     ARENA_INUSE *pInUse;
1152     SUBHEAP *subheap;
1153     HEAP *heapPtr = HEAP_GetPtr( heap );
1154
1155     /* Validate the parameters */
1156
1157     if (!heapPtr) return FALSE;
1158     if (!ptr)  /* Freeing a NULL ptr is doesn't indicate an error in Win2k */
1159     {
1160         WARN("(%08x,%08lx,%08lx): asked to free NULL\n",
1161                    heap, flags, (DWORD)ptr );
1162         return TRUE;
1163     }
1164
1165     flags &= HEAP_NO_SERIALIZE;
1166     flags |= heapPtr->flags;
1167     if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
1168     if (!HEAP_IsRealArena( heap, HEAP_NO_SERIALIZE, ptr, QUIET ))
1169     {
1170         if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
1171         SetLastError( ERROR_INVALID_PARAMETER );
1172         TRACE("(%08x,%08lx,%08lx): returning FALSE\n",
1173                       heap, flags, (DWORD)ptr );
1174         return FALSE;
1175     }
1176
1177     /* Turn the block into a free block */
1178
1179     pInUse  = (ARENA_INUSE *)ptr - 1;
1180     subheap = HEAP_FindSubHeap( heapPtr, pInUse );
1181     HEAP_MakeInUseBlockFree( subheap, pInUse );
1182
1183     if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
1184
1185     TRACE("(%08x,%08lx,%08lx): returning TRUE\n",
1186                   heap, flags, (DWORD)ptr );
1187     return TRUE;
1188 }
1189
1190
1191 /***********************************************************************
1192  *           HeapReAlloc   (KERNEL32.340)
1193  * RETURNS
1194  *      Pointer to reallocated memory block
1195  *      NULL: Failure
1196  */
1197 LPVOID WINAPI HeapReAlloc(
1198               HANDLE heap, /* [in] Handle of heap block */
1199               DWORD flags,   /* [in] Heap reallocation flags */
1200               LPVOID ptr,    /* [in] Address of memory to reallocate */
1201               DWORD size     /* [in] Number of bytes to reallocate */
1202 ) {
1203     ARENA_INUSE *pArena;
1204     DWORD oldSize;
1205     HEAP *heapPtr;
1206     SUBHEAP *subheap;
1207
1208     if (!ptr) return HeapAlloc( heap, flags, size );  /* FIXME: correct? */
1209     if (!(heapPtr = HEAP_GetPtr( heap ))) return FALSE;
1210
1211     /* Validate the parameters */
1212
1213     flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY |
1214              HEAP_REALLOC_IN_PLACE_ONLY;
1215     flags |= heapPtr->flags;
1216     size = (size + 3) & ~3;
1217     if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
1218
1219     if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
1220     if (!HEAP_IsRealArena( heap, HEAP_NO_SERIALIZE, ptr, QUIET ))
1221     {
1222         if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
1223         SetLastError( ERROR_INVALID_PARAMETER );
1224         TRACE("(%08x,%08lx,%08lx,%08lx): returning NULL\n",
1225                       heap, flags, (DWORD)ptr, size );
1226         return NULL;
1227     }
1228
1229     /* Check if we need to grow the block */
1230
1231     pArena = (ARENA_INUSE *)ptr - 1;
1232     pArena->threadId = GetCurrentTask();
1233     subheap = HEAP_FindSubHeap( heapPtr, pArena );
1234     oldSize = (pArena->size & ARENA_SIZE_MASK);
1235     if (size > oldSize)
1236     {
1237         char *pNext = (char *)(pArena + 1) + oldSize;
1238         if ((pNext < (char *)subheap + subheap->size) &&
1239             (*(DWORD *)pNext & ARENA_FLAG_FREE) &&
1240             (oldSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= size))
1241         {
1242             /* The next block is free and large enough */
1243             ARENA_FREE *pFree = (ARENA_FREE *)pNext;
1244             pFree->next->prev = pFree->prev;
1245             pFree->prev->next = pFree->next;
1246             pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree);
1247             if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
1248                                                + size + HEAP_MIN_BLOCK_SIZE))
1249             {
1250                 if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
1251                 SetLastError( ERROR_OUTOFMEMORY );
1252                 return NULL;
1253             }
1254             HEAP_ShrinkBlock( subheap, pArena, size );
1255         }
1256         else  /* Do it the hard way */
1257         {
1258             ARENA_FREE *pNew;
1259             ARENA_INUSE *pInUse;
1260             SUBHEAP *newsubheap;
1261
1262             if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) ||
1263                 !(pNew = HEAP_FindFreeBlock( heapPtr, size, &newsubheap )))
1264             {
1265                 if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
1266                 SetLastError( ERROR_OUTOFMEMORY );
1267                 return NULL;
1268             }
1269
1270             /* Build the in-use arena */
1271
1272             pNew->next->prev = pNew->prev;
1273             pNew->prev->next = pNew->next;
1274             pInUse = (ARENA_INUSE *)pNew;
1275             pInUse->size     = (pInUse->size & ~ARENA_FLAG_FREE)
1276                                + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
1277             pInUse->threadId = GetCurrentTask();
1278             pInUse->magic    = ARENA_INUSE_MAGIC;
1279             HEAP_ShrinkBlock( newsubheap, pInUse, size );
1280             memcpy( pInUse + 1, pArena + 1, oldSize );
1281
1282             /* Free the previous block */
1283
1284             HEAP_MakeInUseBlockFree( subheap, pArena );
1285             subheap = newsubheap;
1286             pArena  = pInUse;
1287         }
1288     }
1289     else HEAP_ShrinkBlock( subheap, pArena, size );  /* Shrink the block */
1290
1291     /* Clear the extra bytes if needed */
1292
1293     if (size > oldSize)
1294     {
1295         if (flags & HEAP_ZERO_MEMORY)
1296             memset( (char *)(pArena + 1) + oldSize, 0,
1297                     (pArena->size & ARENA_SIZE_MASK) - oldSize );
1298         else if (TRACE_ON(heap))
1299             memset( (char *)(pArena + 1) + oldSize, ARENA_INUSE_FILLER,
1300                     (pArena->size & ARENA_SIZE_MASK) - oldSize );
1301     }
1302
1303     /* Return the new arena */
1304
1305     pArena->callerEIP = GET_EIP();
1306     if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
1307
1308     TRACE("(%08x,%08lx,%08lx,%08lx): returning %08lx\n",
1309                   heap, flags, (DWORD)ptr, size, (DWORD)(pArena + 1) );
1310     return (LPVOID)(pArena + 1);
1311 }
1312
1313
1314 /***********************************************************************
1315  *           HeapCompact   (KERNEL32.335)
1316  */
1317 DWORD WINAPI HeapCompact( HANDLE heap, DWORD flags )
1318 {
1319     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1320     return 0;
1321 }
1322
1323
1324 /***********************************************************************
1325  *           HeapLock   (KERNEL32.339)
1326  * Attempts to acquire the critical section object for a specified heap.
1327  *
1328  * RETURNS
1329  *      TRUE: Success
1330  *      FALSE: Failure
1331  */
1332 BOOL WINAPI HeapLock(
1333               HANDLE heap /* [in] Handle of heap to lock for exclusive access */
1334 ) {
1335     HEAP *heapPtr = HEAP_GetPtr( heap );
1336     if (!heapPtr) return FALSE;
1337     EnterCriticalSection( &heapPtr->critSection );
1338     return TRUE;
1339 }
1340
1341
1342 /***********************************************************************
1343  *           HeapUnlock   (KERNEL32.342)
1344  * Releases ownership of the critical section object.
1345  *
1346  * RETURNS
1347  *      TRUE: Success
1348  *      FALSE: Failure
1349  */
1350 BOOL WINAPI HeapUnlock(
1351               HANDLE heap /* [in] Handle to the heap to unlock */
1352 ) {
1353     HEAP *heapPtr = HEAP_GetPtr( heap );
1354     if (!heapPtr) return FALSE;
1355     LeaveCriticalSection( &heapPtr->critSection );
1356     return TRUE;
1357 }
1358
1359
1360 /***********************************************************************
1361  *           HeapSize   (KERNEL32.341)
1362  * RETURNS
1363  *      Size in bytes of allocated memory
1364  *      0xffffffff: Failure
1365  */
1366 DWORD WINAPI HeapSize(
1367              HANDLE heap, /* [in] Handle of heap */
1368              DWORD flags,   /* [in] Heap size control flags */
1369              LPVOID ptr     /* [in] Address of memory to return size for */
1370 ) {
1371     DWORD ret;
1372     HEAP *heapPtr = HEAP_GetPtr( heap );
1373
1374     if (!heapPtr) return FALSE;
1375     flags &= HEAP_NO_SERIALIZE;
1376     flags |= heapPtr->flags;
1377     if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
1378     if (!HEAP_IsRealArena( heap, HEAP_NO_SERIALIZE, ptr, QUIET ))
1379     {
1380         SetLastError( ERROR_INVALID_PARAMETER );
1381         ret = 0xffffffff;
1382     }
1383     else
1384     {
1385         ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1;
1386         ret = pArena->size & ARENA_SIZE_MASK;
1387     }
1388     if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
1389
1390     TRACE("(%08x,%08lx,%08lx): returning %08lx\n",
1391                   heap, flags, (DWORD)ptr, ret );
1392     return ret;
1393 }
1394
1395
1396 /***********************************************************************
1397  *           HeapValidate   (KERNEL32.343)
1398  * Validates a specified heap.
1399  *
1400  * NOTES
1401  *      Flags is ignored.
1402  *
1403  * RETURNS
1404  *      TRUE: Success
1405  *      FALSE: Failure
1406  */
1407 BOOL WINAPI HeapValidate(
1408               HANDLE heap, /* [in] Handle to the heap */
1409               DWORD flags,   /* [in] Bit flags that control access during operation */
1410               LPCVOID block  /* [in] Optional pointer to memory block to validate */
1411 ) {
1412
1413     return HEAP_IsRealArena( heap, flags, block, QUIET );
1414 }
1415
1416
1417 /***********************************************************************
1418  *           HeapWalk   (KERNEL32.344)
1419  * Enumerates the memory blocks in a specified heap.
1420  * See HEAP_Dump() for info on heap structure.
1421  *
1422  * TODO
1423  *   - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
1424  *     PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
1425  *
1426  * RETURNS
1427  *      TRUE: Success
1428  *      FALSE: Failure
1429  */
1430 BOOL WINAPI HeapWalk(
1431               HANDLE heap,               /* [in]  Handle to heap to enumerate */
1432               LPPROCESS_HEAP_ENTRY entry /* [out] Pointer to structure of enumeration info */
1433 ) {
1434     HEAP *heapPtr = HEAP_GetPtr(heap);
1435     SUBHEAP *sub, *currentheap = NULL;
1436     BOOL ret = FALSE;
1437     char *ptr;
1438     int region_index = 0;
1439
1440     if (!heapPtr || !entry)
1441     {
1442         SetLastError(ERROR_INVALID_PARAMETER);
1443         return FALSE;
1444     }
1445
1446     if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
1447
1448     /* set ptr to the next arena to be examined */
1449
1450     if (!entry->lpData) /* first call (init) ? */
1451     {
1452         TRACE("begin walking of heap 0x%08x.\n", heap);
1453         /*HEAP_Dump(heapPtr);*/
1454         currentheap = &heapPtr->subheap;
1455         ptr = (char*)currentheap + currentheap->headerSize;
1456     }
1457     else
1458     {
1459         ptr = entry->lpData;
1460         sub = &heapPtr->subheap;
1461         while (sub)
1462         {
1463             if (((char *)ptr >= (char *)sub) &&
1464                 ((char *)ptr < (char *)sub + sub->size))
1465             {
1466                 currentheap = sub;
1467                 break;
1468             }
1469             sub = sub->next;
1470             region_index++;
1471         }
1472         if (currentheap == NULL)
1473         {
1474             ERR("no matching subheap found, shouldn't happen !\n");
1475             SetLastError(ERROR_NO_MORE_ITEMS);
1476             goto HW_end;
1477         }
1478
1479         ptr += entry->cbData; /* point to next arena */
1480         if (ptr > (char *)currentheap + currentheap->size - 1)
1481         {   /* proceed with next subheap */
1482             if (!(currentheap = currentheap->next))
1483             {  /* successfully finished */
1484                 TRACE("end reached.\n");
1485                 SetLastError(ERROR_NO_MORE_ITEMS);
1486                 goto HW_end;
1487             }
1488             ptr = (char*)currentheap + currentheap->headerSize;
1489         }
1490     }
1491
1492     entry->wFlags = 0;
1493     if (*(DWORD *)ptr & ARENA_FLAG_FREE)
1494     {
1495         ARENA_FREE *pArena = (ARENA_FREE *)ptr;
1496
1497         /*TRACE("free, magic: %04x\n", pArena->magic);*/
1498
1499         entry->lpData = pArena + 1;
1500         entry->cbData = pArena->size & ARENA_SIZE_MASK;
1501         entry->cbOverhead = sizeof(ARENA_FREE);
1502         entry->wFlags = PROCESS_HEAP_UNCOMMITTED_RANGE;
1503     }
1504     else
1505     {
1506         ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
1507
1508         /*TRACE("busy, magic: %04x\n", pArena->magic);*/
1509         
1510         entry->lpData = pArena + 1;
1511         entry->cbData = pArena->size & ARENA_SIZE_MASK;
1512         entry->cbOverhead = sizeof(ARENA_INUSE);
1513         entry->wFlags = PROCESS_HEAP_ENTRY_BUSY;
1514         /* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE
1515         and PROCESS_HEAP_ENTRY_DDESHARE yet */
1516     }
1517
1518     entry->iRegionIndex = region_index;
1519
1520     /* first element of heap ? */
1521     if (ptr == (char *)(currentheap + currentheap->headerSize))
1522     {
1523         entry->wFlags |= PROCESS_HEAP_REGION;
1524         entry->Foo.Region.dwCommittedSize = currentheap->commitSize;
1525         entry->Foo.Region.dwUnCommittedSize =
1526                 currentheap->size - currentheap->commitSize;
1527         entry->Foo.Region.lpFirstBlock = /* first valid block */
1528                 currentheap + currentheap->headerSize;
1529         entry->Foo.Region.lpLastBlock  = /* first invalid block */
1530                 currentheap + currentheap->size;
1531     }
1532     ret = TRUE;
1533
1534 HW_end:
1535     if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
1536
1537     return ret;
1538 }
1539
1540
1541 /***********************************************************************
1542  *           HEAP_CreateSystemHeap
1543  *
1544  * Create the system heap.
1545  */
1546 BOOL HEAP_CreateSystemHeap(void)
1547 {
1548     SYSTEM_HEAP_DESCR *descr;
1549     HANDLE heap;
1550     HEAP *heapPtr;
1551     int created;
1552
1553     HANDLE map = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE,
1554                                      0, HEAP_DEF_SIZE, "__SystemHeap" );
1555     if (!map) return FALSE;
1556     created = (GetLastError() != ERROR_ALREADY_EXISTS);
1557
1558     if (!(heapPtr = MapViewOfFileEx( map, FILE_MAP_ALL_ACCESS, 0, 0, 0, SYSTEM_HEAP_BASE )))
1559     {
1560         /* pre-defined address not available, use any one */
1561         fprintf( stderr, "Warning: system heap base address %p not available\n",
1562                  SYSTEM_HEAP_BASE );
1563         if (!(heapPtr = MapViewOfFile( map, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
1564         {
1565             CloseHandle( map );
1566             return FALSE;
1567         }
1568     }
1569     heap = (HANDLE)heapPtr;
1570
1571     if (created)  /* newly created heap */
1572     {
1573         HEAP_InitSubHeap( heapPtr, heapPtr, HEAP_WINE_SHARED, 0, HEAP_DEF_SIZE );
1574         HeapLock( heap );
1575         descr = heapPtr->private = HeapAlloc( heap, HEAP_ZERO_MEMORY, sizeof(*descr) );
1576         assert( descr );
1577     }
1578     else
1579     {
1580         /* wait for the heap to be initialized */
1581         while (!heapPtr->private) Sleep(1);
1582         HeapLock( heap );
1583         /* remap it to the right address if necessary */
1584         if (heapPtr->subheap.heap != heapPtr)
1585         {
1586             void *base = heapPtr->subheap.heap;
1587             HeapUnlock( heap );
1588             UnmapViewOfFile( heapPtr );
1589             if (!(heapPtr = MapViewOfFileEx( map, FILE_MAP_ALL_ACCESS, 0, 0, 0, base )))
1590             {
1591                 fprintf( stderr, "Couldn't map system heap at the correct address (%p)\n", base );
1592                 CloseHandle( map );
1593                 return FALSE;
1594             }
1595             heap = (HANDLE)heapPtr;
1596             HeapLock( heap );
1597         }
1598         descr = heapPtr->private;
1599         assert( descr );
1600     }
1601     SystemHeap = heap;
1602     SystemHeapDescr = descr;
1603     HeapUnlock( heap );
1604     CloseHandle( map );
1605     return TRUE;
1606 }
1607
1608
1609 /***********************************************************************
1610  *           GetProcessHeap    (KERNEL32.259)
1611  */
1612 HANDLE WINAPI GetProcessHeap(void)
1613 {
1614     return (HANDLE)processHeap;
1615 }
1616
1617
1618 /***********************************************************************
1619  *           GetProcessHeaps    (KERNEL32.376)
1620  */
1621 DWORD WINAPI GetProcessHeaps( DWORD count, HANDLE *heaps )
1622 {
1623     DWORD total;
1624     HEAP *ptr;
1625
1626     if (!processHeap) return 0;  /* should never happen */
1627     total = 1;  /* main heap */
1628     EnterCriticalSection( &processHeap->critSection );
1629     for (ptr = firstHeap; ptr; ptr = ptr->next) total++;
1630     if (total <= count)
1631     {
1632         *heaps++ = (HANDLE)processHeap;
1633         for (ptr = firstHeap; ptr; ptr = ptr->next) *heaps++ = (HANDLE)ptr;
1634     }
1635     LeaveCriticalSection( &processHeap->critSection );
1636     return total;
1637 }
1638
1639
1640 /***********************************************************************
1641  *           HEAP_strdupA
1642  */
1643 LPSTR HEAP_strdupA( HANDLE heap, DWORD flags, LPCSTR str )
1644 {
1645     LPSTR p = HeapAlloc( heap, flags, strlen(str) + 1 );
1646     if(p) {
1647         SET_EIP(p);
1648         strcpy( p, str );
1649     }
1650     return p;
1651 }
1652
1653
1654 /***********************************************************************
1655  *           HEAP_strdupW
1656  */
1657 LPWSTR HEAP_strdupW( HANDLE heap, DWORD flags, LPCWSTR str )
1658 {
1659     INT len = lstrlenW(str) + 1;
1660     LPWSTR p = HeapAlloc( heap, flags, len * sizeof(WCHAR) );
1661     if(p) {
1662         SET_EIP(p);
1663         lstrcpyW( p, str );
1664     }
1665     return p;
1666 }
1667
1668
1669 /***********************************************************************
1670  *           HEAP_strdupAtoW
1671  */
1672 LPWSTR HEAP_strdupAtoW( HANDLE heap, DWORD flags, LPCSTR str )
1673 {
1674     LPWSTR ret;
1675
1676     if (!str) return NULL;
1677     ret = HeapAlloc( heap, flags, (strlen(str)+1) * sizeof(WCHAR) );
1678     if (ret) {
1679         SET_EIP(ret);
1680         lstrcpyAtoW( ret, str );
1681     }
1682     return ret;
1683 }
1684
1685
1686 /***********************************************************************
1687  *           HEAP_strdupWtoA
1688  */
1689 LPSTR HEAP_strdupWtoA( HANDLE heap, DWORD flags, LPCWSTR str )
1690 {
1691     LPSTR ret;
1692     INT len;
1693
1694     if (!str) return NULL;
1695     len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
1696     ret = HeapAlloc( heap, flags, len );
1697     if(ret) {
1698         SET_EIP(ret);
1699         WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
1700     }
1701     return ret;
1702 }
1703
1704
1705
1706 /***********************************************************************
1707  * 32-bit local heap functions (Win95; undocumented)
1708  */
1709
1710 #define HTABLE_SIZE      0x10000
1711 #define HTABLE_PAGESIZE  0x1000
1712 #define HTABLE_NPAGES    (HTABLE_SIZE / HTABLE_PAGESIZE)
1713
1714 #include "pshpack1.h"
1715 typedef struct _LOCAL32HEADER
1716 {
1717     WORD     freeListFirst[HTABLE_NPAGES];
1718     WORD     freeListSize[HTABLE_NPAGES];
1719     WORD     freeListLast[HTABLE_NPAGES];
1720
1721     DWORD    selectorTableOffset;
1722     WORD     selectorTableSize;
1723     WORD     selectorDelta;
1724
1725     DWORD    segment;
1726     LPBYTE   base;
1727
1728     DWORD    limit;
1729     DWORD    flags;
1730
1731     DWORD    magic;
1732     HANDLE heap;
1733
1734 } LOCAL32HEADER;
1735 #include "poppack.h"
1736
1737 #define LOCAL32_MAGIC    ((DWORD)('L' | ('H'<<8) | ('3'<<16) | ('2'<<24)))
1738
1739 /***********************************************************************
1740  *           Local32Init   (KERNEL.208)
1741  */
1742 HANDLE WINAPI Local32Init16( WORD segment, DWORD tableSize,
1743                              DWORD heapSize, DWORD flags )
1744 {
1745     DWORD totSize, segSize = 0;
1746     LPBYTE base;
1747     LOCAL32HEADER *header;
1748     HEAP *heap;
1749     WORD *selectorTable;
1750     WORD selectorEven, selectorOdd;
1751     int i, nrBlocks;
1752
1753     /* Determine new heap size */
1754
1755     if ( segment )
1756     {
1757         if ( (segSize = GetSelectorLimit16( segment )) == 0 )
1758             return 0;
1759         else
1760             segSize++;
1761     }
1762
1763     if ( heapSize == -1L )
1764         heapSize = 1024L*1024L;   /* FIXME */
1765
1766     heapSize = (heapSize + 0xffff) & 0xffff0000;
1767     segSize  = (segSize  + 0x0fff) & 0xfffff000;
1768     totSize  = segSize + HTABLE_SIZE + heapSize;
1769
1770
1771     /* Allocate memory and initialize heap */
1772
1773     if ( !(base = VirtualAlloc( NULL, totSize, MEM_RESERVE, PAGE_READWRITE )) )
1774         return 0;
1775
1776     if ( !VirtualAlloc( base, segSize + HTABLE_PAGESIZE, 
1777                         MEM_COMMIT, PAGE_READWRITE ) )
1778     {
1779         VirtualFree( base, 0, MEM_RELEASE );
1780         return 0;
1781     }
1782
1783     heap = (HEAP *)(base + segSize + HTABLE_SIZE);
1784     if ( !HEAP_InitSubHeap( heap, (LPVOID)heap, 0, 0x10000, heapSize ) )
1785     {
1786         VirtualFree( base, 0, MEM_RELEASE );
1787         return 0;
1788     }
1789
1790
1791     /* Set up header and handle table */
1792     
1793     header = (LOCAL32HEADER *)(base + segSize);
1794     header->base    = base;
1795     header->limit   = HTABLE_PAGESIZE-1;
1796     header->flags   = 0;
1797     header->magic   = LOCAL32_MAGIC;
1798     header->heap    = (HANDLE)heap;
1799
1800     header->freeListFirst[0] = sizeof(LOCAL32HEADER);
1801     header->freeListLast[0]  = HTABLE_PAGESIZE - 4;
1802     header->freeListSize[0]  = (HTABLE_PAGESIZE - sizeof(LOCAL32HEADER)) / 4;
1803
1804     for (i = header->freeListFirst[0]; i < header->freeListLast[0]; i += 4)
1805         *(DWORD *)((LPBYTE)header + i) = i+4;
1806
1807     header->freeListFirst[1] = 0xffff;
1808
1809
1810     /* Set up selector table */
1811   
1812     nrBlocks      = (totSize + 0x7fff) >> 15; 
1813     selectorTable = (LPWORD) HeapAlloc( header->heap,  0, nrBlocks * 2 );
1814     selectorEven  = SELECTOR_AllocBlock( base, totSize, 
1815                                          SEGMENT_DATA, FALSE, FALSE );
1816     selectorOdd   = SELECTOR_AllocBlock( base + 0x8000, totSize - 0x8000, 
1817                                          SEGMENT_DATA, FALSE, FALSE );
1818     
1819     if ( !selectorTable || !selectorEven || !selectorOdd )
1820     {
1821         if ( selectorTable ) HeapFree( header->heap, 0, selectorTable );
1822         if ( selectorEven  ) SELECTOR_FreeBlock( selectorEven, totSize >> 16 );
1823         if ( selectorOdd   ) SELECTOR_FreeBlock( selectorOdd, (totSize-0x8000) >> 16 );
1824         HeapDestroy( header->heap );
1825         VirtualFree( base, 0, MEM_RELEASE );
1826         return 0;
1827     }
1828
1829     header->selectorTableOffset = (LPBYTE)selectorTable - header->base;
1830     header->selectorTableSize   = nrBlocks * 4;  /* ??? Win95 does it this way! */
1831     header->selectorDelta       = selectorEven - selectorOdd;
1832     header->segment             = segment? segment : selectorEven;
1833
1834     for (i = 0; i < nrBlocks; i++)
1835         selectorTable[i] = (i & 1)? selectorOdd  + ((i >> 1) << __AHSHIFT)
1836                                   : selectorEven + ((i >> 1) << __AHSHIFT);
1837
1838     /* Move old segment */
1839
1840     if ( segment )
1841     {
1842         /* FIXME: This is somewhat ugly and relies on implementation
1843                   details about 16-bit global memory handles ... */
1844
1845         LPBYTE oldBase = (LPBYTE)GetSelectorBase( segment );
1846         memcpy( base, oldBase, segSize );
1847         GLOBAL_MoveBlock( segment, base, totSize );
1848         HeapFree( SystemHeap, 0, oldBase );
1849     }
1850     
1851     return (HANDLE)header;
1852 }
1853
1854 /***********************************************************************
1855  *           Local32_SearchHandle
1856  */
1857 static LPDWORD Local32_SearchHandle( LOCAL32HEADER *header, DWORD addr )
1858 {
1859     LPDWORD handle;
1860
1861     for ( handle = (LPDWORD)((LPBYTE)header + sizeof(LOCAL32HEADER));
1862           handle < (LPDWORD)((LPBYTE)header + header->limit);
1863           handle++)
1864     {
1865         if (*handle == addr)
1866             return handle;
1867     }
1868
1869     return NULL;
1870 }
1871
1872 /***********************************************************************
1873  *           Local32_ToHandle
1874  */
1875 static VOID Local32_ToHandle( LOCAL32HEADER *header, INT16 type, 
1876                               DWORD addr, LPDWORD *handle, LPBYTE *ptr )
1877 {
1878     *handle = NULL;
1879     *ptr    = NULL;
1880
1881     switch (type)
1882     {
1883         case -2:    /* 16:16 pointer, no handles */
1884             *ptr    = PTR_SEG_TO_LIN( addr );
1885             *handle = (LPDWORD)*ptr;
1886             break;
1887
1888         case -1:    /* 32-bit offset, no handles */
1889             *ptr    = header->base + addr;
1890             *handle = (LPDWORD)*ptr;
1891             break;
1892
1893         case 0:     /* handle */
1894             if (    addr >= sizeof(LOCAL32HEADER) 
1895                  && addr <  header->limit && !(addr & 3) 
1896                  && *(LPDWORD)((LPBYTE)header + addr) >= HTABLE_SIZE )
1897             {
1898                 *handle = (LPDWORD)((LPBYTE)header + addr);
1899                 *ptr    = header->base + **handle;
1900             }
1901             break;
1902
1903         case 1:     /* 16:16 pointer */
1904             *ptr    = PTR_SEG_TO_LIN( addr );
1905             *handle = Local32_SearchHandle( header, *ptr - header->base );
1906             break;
1907
1908         case 2:     /* 32-bit offset */
1909             *ptr    = header->base + addr;
1910             *handle = Local32_SearchHandle( header, *ptr - header->base );
1911             break;
1912     }
1913 }
1914
1915 /***********************************************************************
1916  *           Local32_FromHandle
1917  */
1918 static VOID Local32_FromHandle( LOCAL32HEADER *header, INT16 type, 
1919                                 DWORD *addr, LPDWORD handle, LPBYTE ptr )
1920 {
1921     switch (type)
1922     {
1923         case -2:    /* 16:16 pointer */
1924         case  1:
1925         {
1926             WORD *selTable = (LPWORD)(header->base + header->selectorTableOffset);
1927             DWORD offset   = (LPBYTE)ptr - header->base;
1928             *addr = MAKELONG( offset & 0x7fff, selTable[offset >> 15] ); 
1929         }
1930         break;
1931
1932         case -1:    /* 32-bit offset */
1933         case  2:
1934             *addr = ptr - header->base;
1935             break;
1936
1937         case  0:    /* handle */
1938             *addr = (LPBYTE)handle - (LPBYTE)header;
1939             break;
1940     }
1941 }
1942
1943 /***********************************************************************
1944  *           Local32Alloc   (KERNEL.209)
1945  */
1946 DWORD WINAPI Local32Alloc16( HANDLE heap, DWORD size, INT16 type, DWORD flags )
1947 {
1948     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
1949     LPDWORD handle;
1950     LPBYTE ptr;
1951     DWORD addr;
1952
1953     /* Allocate memory */
1954     ptr = HeapAlloc( header->heap, 
1955                      (flags & LMEM_MOVEABLE)? HEAP_ZERO_MEMORY : 0, size );
1956     if (!ptr) return 0;
1957
1958
1959     /* Allocate handle if requested */
1960     if (type >= 0)
1961     {
1962         int page, i;
1963
1964         /* Find first page of handle table with free slots */
1965         for (page = 0; page < HTABLE_NPAGES; page++)
1966             if (header->freeListFirst[page] != 0)
1967                 break;
1968         if (page == HTABLE_NPAGES)
1969         {
1970             WARN("Out of handles!\n" );
1971             HeapFree( header->heap, 0, ptr );
1972             return 0;
1973         }
1974
1975         /* If virgin page, initialize it */
1976         if (header->freeListFirst[page] == 0xffff)
1977         {
1978             if ( !VirtualAlloc( (LPBYTE)header + (page << 12), 
1979                                 0x1000, MEM_COMMIT, PAGE_READWRITE ) )
1980             {
1981                 WARN("Cannot grow handle table!\n" );
1982                 HeapFree( header->heap, 0, ptr );
1983                 return 0;
1984             }
1985             
1986             header->limit += HTABLE_PAGESIZE;
1987
1988             header->freeListFirst[page] = 0;
1989             header->freeListLast[page]  = HTABLE_PAGESIZE - 4;
1990             header->freeListSize[page]  = HTABLE_PAGESIZE / 4;
1991            
1992             for (i = 0; i < HTABLE_PAGESIZE; i += 4)
1993                 *(DWORD *)((LPBYTE)header + i) = i+4;
1994
1995             if (page < HTABLE_NPAGES-1) 
1996                 header->freeListFirst[page+1] = 0xffff;
1997         }
1998
1999         /* Allocate handle slot from page */
2000         handle = (LPDWORD)((LPBYTE)header + header->freeListFirst[page]);
2001         if (--header->freeListSize[page] == 0)
2002             header->freeListFirst[page] = header->freeListLast[page] = 0;
2003         else
2004             header->freeListFirst[page] = *handle;
2005
2006         /* Store 32-bit offset in handle slot */
2007         *handle = ptr - header->base;
2008     }
2009     else
2010     {
2011         handle = (LPDWORD)ptr;
2012         header->flags |= 1;
2013     }
2014
2015
2016     /* Convert handle to requested output type */
2017     Local32_FromHandle( header, type, &addr, handle, ptr );
2018     return addr;
2019 }
2020
2021 /***********************************************************************
2022  *           Local32ReAlloc   (KERNEL.210)
2023  */
2024 DWORD WINAPI Local32ReAlloc16( HANDLE heap, DWORD addr, INT16 type,
2025                              DWORD size, DWORD flags )
2026 {
2027     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
2028     LPDWORD handle;
2029     LPBYTE ptr;
2030
2031     if (!addr)
2032         return Local32Alloc16( heap, size, type, flags );
2033
2034     /* Retrieve handle and pointer */
2035     Local32_ToHandle( header, type, addr, &handle, &ptr );
2036     if (!handle) return FALSE;
2037
2038     /* Reallocate memory block */
2039     ptr = HeapReAlloc( header->heap, 
2040                        (flags & LMEM_MOVEABLE)? HEAP_ZERO_MEMORY : 0, 
2041                        ptr, size );
2042     if (!ptr) return 0;
2043
2044     /* Modify handle */
2045     if (type >= 0)
2046         *handle = ptr - header->base;
2047     else
2048         handle = (LPDWORD)ptr;
2049
2050     /* Convert handle to requested output type */
2051     Local32_FromHandle( header, type, &addr, handle, ptr );
2052     return addr;
2053 }
2054
2055 /***********************************************************************
2056  *           Local32Free   (KERNEL.211)
2057  */
2058 BOOL WINAPI Local32Free16( HANDLE heap, DWORD addr, INT16 type )
2059 {
2060     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
2061     LPDWORD handle;
2062     LPBYTE ptr;
2063
2064     /* Retrieve handle and pointer */
2065     Local32_ToHandle( header, type, addr, &handle, &ptr );
2066     if (!handle) return FALSE;
2067
2068     /* Free handle if necessary */
2069     if (type >= 0)
2070     {
2071         int offset = (LPBYTE)handle - (LPBYTE)header;
2072         int page   = offset >> 12;
2073
2074         /* Return handle slot to page free list */
2075         if (header->freeListSize[page]++ == 0)
2076             header->freeListFirst[page] = header->freeListLast[page]  = offset;
2077         else
2078             *(LPDWORD)((LPBYTE)header + header->freeListLast[page]) = offset,
2079             header->freeListLast[page] = offset;
2080
2081         *handle = 0;
2082
2083         /* Shrink handle table when possible */
2084         while (page > 0 && header->freeListSize[page] == HTABLE_PAGESIZE / 4)
2085         {
2086             if ( VirtualFree( (LPBYTE)header + 
2087                               (header->limit & ~(HTABLE_PAGESIZE-1)),
2088                               HTABLE_PAGESIZE, MEM_DECOMMIT ) )
2089                 break;
2090
2091             header->limit -= HTABLE_PAGESIZE;
2092             header->freeListFirst[page] = 0xffff;
2093             page--;
2094         }
2095     }
2096
2097     /* Free memory */
2098     return HeapFree( header->heap, 0, ptr );
2099 }
2100
2101 /***********************************************************************
2102  *           Local32Translate   (KERNEL.213)
2103  */
2104 DWORD WINAPI Local32Translate16( HANDLE heap, DWORD addr, INT16 type1, INT16 type2 )
2105 {
2106     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
2107     LPDWORD handle;
2108     LPBYTE ptr;
2109
2110     Local32_ToHandle( header, type1, addr, &handle, &ptr );
2111     if (!handle) return 0;
2112
2113     Local32_FromHandle( header, type2, &addr, handle, ptr );
2114     return addr;
2115 }
2116
2117 /***********************************************************************
2118  *           Local32Size   (KERNEL.214)
2119  */
2120 DWORD WINAPI Local32Size16( HANDLE heap, DWORD addr, INT16 type )
2121 {
2122     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
2123     LPDWORD handle;
2124     LPBYTE ptr;
2125
2126     Local32_ToHandle( header, type, addr, &handle, &ptr );
2127     if (!handle) return 0;
2128
2129     return HeapSize( header->heap, 0, ptr );
2130 }
2131
2132 /***********************************************************************
2133  *           Local32ValidHandle   (KERNEL.215)
2134  */
2135 BOOL WINAPI Local32ValidHandle16( HANDLE heap, WORD addr )
2136 {
2137     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
2138     LPDWORD handle;
2139     LPBYTE ptr;
2140
2141     Local32_ToHandle( header, 0, addr, &handle, &ptr );
2142     return handle != NULL;
2143 }
2144
2145 /***********************************************************************
2146  *           Local32GetSegment   (KERNEL.229)
2147  */
2148 WORD WINAPI Local32GetSegment16( HANDLE heap )
2149 {
2150     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
2151     return header->segment;
2152 }
2153
2154 /***********************************************************************
2155  *           Local32_GetHeap
2156  */
2157 static LOCAL32HEADER *Local32_GetHeap( HGLOBAL16 handle )
2158 {
2159     WORD selector = GlobalHandleToSel16( handle );
2160     DWORD base  = GetSelectorBase( selector ); 
2161     DWORD limit = GetSelectorLimit16( selector ); 
2162
2163     /* Hmmm. This is a somewhat stupid heuristic, but Windows 95 does
2164        it this way ... */
2165
2166     if ( limit > 0x10000 && ((LOCAL32HEADER *)base)->magic == LOCAL32_MAGIC )
2167         return (LOCAL32HEADER *)base;
2168
2169     base  += 0x10000;
2170     limit -= 0x10000;
2171
2172     if ( limit > 0x10000 && ((LOCAL32HEADER *)base)->magic == LOCAL32_MAGIC )
2173         return (LOCAL32HEADER *)base;
2174
2175     return NULL;
2176 }
2177
2178 /***********************************************************************
2179  *           Local32Info   (KERNEL.444)  (TOOLHELP.84)
2180  */
2181 BOOL16 WINAPI Local32Info16( LOCAL32INFO *pLocal32Info, HGLOBAL16 handle )
2182 {
2183     SUBHEAP *heapPtr;
2184     LPBYTE ptr;
2185     int i;
2186
2187     LOCAL32HEADER *header = Local32_GetHeap( handle );
2188     if ( !header ) return FALSE;
2189
2190     if ( !pLocal32Info || pLocal32Info->dwSize < sizeof(LOCAL32INFO) )
2191         return FALSE;
2192
2193     heapPtr = (SUBHEAP *)HEAP_GetPtr( header->heap );
2194     pLocal32Info->dwMemReserved = heapPtr->size;
2195     pLocal32Info->dwMemCommitted = heapPtr->commitSize;
2196     pLocal32Info->dwTotalFree = 0L;
2197     pLocal32Info->dwLargestFreeBlock = 0L;
2198
2199     /* Note: Local32 heaps always have only one subheap! */
2200     ptr = (LPBYTE)heapPtr + heapPtr->headerSize;
2201     while ( ptr < (LPBYTE)heapPtr + heapPtr->size )
2202     {
2203         if (*(DWORD *)ptr & ARENA_FLAG_FREE)
2204         {
2205             ARENA_FREE *pArena = (ARENA_FREE *)ptr;
2206             DWORD size = (pArena->size & ARENA_SIZE_MASK);
2207             ptr += sizeof(*pArena) + size;
2208
2209             pLocal32Info->dwTotalFree += size;
2210             if ( size > pLocal32Info->dwLargestFreeBlock )
2211                 pLocal32Info->dwLargestFreeBlock = size;
2212         }
2213         else
2214         {
2215             ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
2216             DWORD size = (pArena->size & ARENA_SIZE_MASK);
2217             ptr += sizeof(*pArena) + size;
2218         }
2219     }
2220
2221     pLocal32Info->dwcFreeHandles = 0;
2222     for ( i = 0; i < HTABLE_NPAGES; i++ )
2223     {
2224         if ( header->freeListFirst[i] == 0xffff ) break;
2225         pLocal32Info->dwcFreeHandles += header->freeListSize[i];
2226     }
2227     pLocal32Info->dwcFreeHandles += (HTABLE_NPAGES - i) * HTABLE_PAGESIZE/4;
2228
2229     return TRUE;
2230 }
2231
2232 /***********************************************************************
2233  *           Local32First   (KERNEL.445)  (TOOLHELP.85)
2234  */
2235 BOOL16 WINAPI Local32First16( LOCAL32ENTRY *pLocal32Entry, HGLOBAL16 handle )
2236 {
2237     FIXME("(%p, %04X): stub!\n", pLocal32Entry, handle );
2238     return FALSE;
2239 }
2240
2241 /***********************************************************************
2242  *           Local32Next   (KERNEL.446)  (TOOLHELP.86)
2243  */
2244 BOOL16 WINAPI Local32Next16( LOCAL32ENTRY *pLocal32Entry )
2245 {
2246     FIXME("(%p): stub!\n", pLocal32Entry );
2247     return FALSE;
2248 }
2249