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