Set %fs and %gs in the register context to their current value when
[wine] / dlls / kernel / heap.c
1 /*
2  * Win32 heap functions
3  *
4  * Copyright 1995, 1996 Alexandre Julliard
5  * Copyright 1996 Huw Davies
6  * Copyright 1998 Ulrich Weigand
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <time.h>
32 #ifdef HAVE_SYS_PARAM_H
33 #include <sys/param.h>
34 #endif
35 #ifdef HAVE_SYS_SYSCTL_H
36 #include <sys/sysctl.h>
37 #endif
38 #ifdef HAVE_UNISTD_H
39 # include <unistd.h>
40 #endif
41
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winerror.h"
45 #include "winnt.h"
46 #include "winreg.h"
47 #include "winternl.h"
48 #include "excpt.h"
49 #include "thread.h"
50 #include "wine/exception.h"
51 #include "wine/debug.h"
52
53 WINE_DEFAULT_DEBUG_CHANNEL(heap);
54
55 /* address where we try to map the system heap */
56 #define SYSTEM_HEAP_BASE  ((void*)0x65430000)
57 #define SYSTEM_HEAP_SIZE  0x100000   /* Default heap size = 1Mb */
58
59 static HANDLE systemHeap;   /* globally shared heap */
60
61
62
63 /* filter for page-fault exceptions */
64 /* It is possible for a bogus global pointer to cause a */
65 /* page zero reference, so I include EXCEPTION_PRIV_INSTRUCTION too. */
66 static WINE_EXCEPTION_FILTER(page_fault)
67 {
68     switch (GetExceptionCode()) {
69         case (EXCEPTION_ACCESS_VIOLATION):
70         case (EXCEPTION_PRIV_INSTRUCTION):
71            return EXCEPTION_EXECUTE_HANDLER;
72         default:
73            return EXCEPTION_CONTINUE_SEARCH;
74     }
75 }
76
77 /***********************************************************************
78  *           HEAP_CreateSystemHeap
79  *
80  * Create the system heap.
81  */
82 inline static HANDLE HEAP_CreateSystemHeap(void)
83 {
84     int created;
85     void *base;
86     HANDLE map, event;
87     UNICODE_STRING event_name;
88     OBJECT_ATTRIBUTES event_attr;
89
90     if (!(map = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE,
91                                     0, SYSTEM_HEAP_SIZE, "__SystemHeap" ))) return 0;
92     created = (GetLastError() != ERROR_ALREADY_EXISTS);
93
94     if (!(base = MapViewOfFileEx( map, FILE_MAP_ALL_ACCESS, 0, 0, 0, SYSTEM_HEAP_BASE )))
95     {
96         /* pre-defined address not available */
97         ERR( "system heap base address %p not available\n", SYSTEM_HEAP_BASE );
98         return 0;
99     }
100
101     /* create the system heap event */
102     RtlCreateUnicodeStringFromAsciiz( &event_name, "__SystemHeapEvent" );
103     event_attr.Length = sizeof(event_attr);
104     event_attr.RootDirectory = 0;
105     event_attr.ObjectName = &event_name;
106     event_attr.Attributes = 0;
107     event_attr.SecurityDescriptor = NULL;
108     event_attr.SecurityQualityOfService = NULL;
109     NtCreateEvent( &event, EVENT_ALL_ACCESS, &event_attr, TRUE, FALSE );
110
111     if (created)  /* newly created heap */
112     {
113         systemHeap = RtlCreateHeap( HEAP_SHARED, base, SYSTEM_HEAP_SIZE,
114                                     SYSTEM_HEAP_SIZE, NULL, NULL );
115         NtSetEvent( event, NULL );
116     }
117     else
118     {
119         /* wait for the heap to be initialized */
120         WaitForSingleObject( event, INFINITE );
121         systemHeap = (HANDLE)base;
122     }
123     CloseHandle( map );
124     return systemHeap;
125 }
126
127
128 /***********************************************************************
129  *           HeapCreate   (KERNEL32.@)
130  * RETURNS
131  *      Handle of heap: Success
132  *      NULL: Failure
133  */
134 HANDLE WINAPI HeapCreate(
135                 DWORD flags,       /* [in] Heap allocation flag */
136                 SIZE_T initialSize, /* [in] Initial heap size */
137                 SIZE_T maxSize      /* [in] Maximum heap size */
138 ) {
139     HANDLE ret;
140
141     if ( flags & HEAP_SHARED )
142     {
143         if (!systemHeap) HEAP_CreateSystemHeap();
144         else WARN( "Shared Heap requested, returning system heap.\n" );
145         ret = systemHeap;
146     }
147     else
148     {
149         ret = RtlCreateHeap( flags, NULL, maxSize, initialSize, NULL, NULL );
150         if (!ret) SetLastError( ERROR_NOT_ENOUGH_MEMORY );
151     }
152     return ret;
153 }
154
155
156 /***********************************************************************
157  *           HeapDestroy   (KERNEL32.@)
158  * RETURNS
159  *      TRUE: Success
160  *      FALSE: Failure
161  */
162 BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
163 {
164     if (heap == systemHeap)
165     {
166         WARN( "attempt to destroy system heap, returning TRUE!\n" );
167         return TRUE;
168     }
169     if (!RtlDestroyHeap( heap )) return TRUE;
170     SetLastError( ERROR_INVALID_HANDLE );
171     return FALSE;
172 }
173
174
175 /***********************************************************************
176  *           HeapCompact   (KERNEL32.@)
177  */
178 SIZE_T WINAPI HeapCompact( HANDLE heap, DWORD flags )
179 {
180     return RtlCompactHeap( heap, flags );
181 }
182
183
184 /***********************************************************************
185  *           HeapValidate   (KERNEL32.@)
186  * Validates a specified heap.
187  *
188  * NOTES
189  *      Flags is ignored.
190  *
191  * RETURNS
192  *      TRUE: Success
193  *      FALSE: Failure
194  */
195 BOOL WINAPI HeapValidate(
196               HANDLE heap, /* [in] Handle to the heap */
197               DWORD flags,   /* [in] Bit flags that control access during operation */
198               LPCVOID block  /* [in] Optional pointer to memory block to validate */
199 ) {
200     return RtlValidateHeap( heap, flags, block );
201 }
202
203
204 /***********************************************************************
205  *           HeapWalk   (KERNEL32.@)
206  * Enumerates the memory blocks in a specified heap.
207  *
208  * TODO
209  *   - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
210  *     PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
211  *
212  * RETURNS
213  *      TRUE: Success
214  *      FALSE: Failure
215  */
216 BOOL WINAPI HeapWalk(
217               HANDLE heap,               /* [in]  Handle to heap to enumerate */
218               LPPROCESS_HEAP_ENTRY entry /* [out] Pointer to structure of enumeration info */
219 ) {
220     NTSTATUS ret = RtlWalkHeap( heap, entry );
221     if (ret) SetLastError( RtlNtStatusToDosError(ret) );
222     return !ret;
223 }
224
225
226 /***********************************************************************
227  *           HeapLock   (KERNEL32.@)
228  * Attempts to acquire the critical section object for a specified heap.
229  *
230  * RETURNS
231  *      TRUE: Success
232  *      FALSE: Failure
233  */
234 BOOL WINAPI HeapLock(
235               HANDLE heap /* [in] Handle of heap to lock for exclusive access */
236 ) {
237     return RtlLockHeap( heap );
238 }
239
240
241 /***********************************************************************
242  *           HeapUnlock   (KERNEL32.@)
243  * Releases ownership of the critical section object.
244  *
245  * RETURNS
246  *      TRUE: Success
247  *      FALSE: Failure
248  */
249 BOOL WINAPI HeapUnlock(
250               HANDLE heap /* [in] Handle to the heap to unlock */
251 ) {
252     return RtlUnlockHeap( heap );
253 }
254
255
256 /***********************************************************************
257  *           GetProcessHeap    (KERNEL32.@)
258  */
259 HANDLE WINAPI GetProcessHeap(void)
260 {
261     return NtCurrentTeb()->Peb->ProcessHeap;
262 }
263
264
265 /***********************************************************************
266  *           GetProcessHeaps    (KERNEL32.@)
267  */
268 DWORD WINAPI GetProcessHeaps( DWORD count, HANDLE *heaps )
269 {
270     return RtlGetProcessHeaps( count, heaps );
271 }
272
273
274 /* These are needed so that we can call the functions from inside kernel itself */
275
276 LPVOID WINAPI HeapAlloc( HANDLE heap, DWORD flags, SIZE_T size )
277 {
278     return RtlAllocateHeap( heap, flags, size );
279 }
280
281 BOOL WINAPI HeapFree( HANDLE heap, DWORD flags, LPVOID ptr )
282 {
283     return RtlFreeHeap( heap, flags, ptr );
284 }
285
286 LPVOID WINAPI HeapReAlloc( HANDLE heap, DWORD flags, LPVOID ptr, SIZE_T size )
287 {
288     return RtlReAllocateHeap( heap, flags, ptr, size );
289 }
290
291 SIZE_T WINAPI HeapSize( HANDLE heap, DWORD flags, LPVOID ptr )
292 {
293     return RtlSizeHeap( heap, flags, ptr );
294 }
295
296 /*
297  * Win32 Global heap functions (GlobalXXX).
298  * These functions included in Win32 for compatibility with 16 bit Windows
299  * Especially the moveable blocks and handles are oldish.
300  * But the ability to directly allocate memory with GPTR and LPTR is widely
301  * used.
302  *
303  * The handle stuff looks horrible, but it's implemented almost like Win95
304  * does it.
305  *
306  */
307
308 #define MAGIC_GLOBAL_USED 0x5342
309 #define GLOBAL_LOCK_MAX   0xFF
310 #define HANDLE_TO_INTERN(h)  ((PGLOBAL32_INTERN)(((char *)(h))-2))
311 #define INTERN_TO_HANDLE(i)  ((HGLOBAL) &((i)->Pointer))
312 #define POINTER_TO_HANDLE(p) (*(((HGLOBAL *)(p))-2))
313 #define ISHANDLE(h)          (((ULONG_PTR)(h)&2)!=0)
314 #define ISPOINTER(h)         (((ULONG_PTR)(h)&2)==0)
315 /* align the storage needed for the HGLOBAL on an 8byte boundary thus
316  * GlobalAlloc/GlobalReAlloc'ing with GMEM_MOVEABLE of memory with
317  * size = 8*k, where k=1,2,3,... alloc's exactly the given size.
318  * The Minolta DiMAGE Image Viewer heavily relies on this, corrupting
319  * the output jpeg's > 1 MB if not */
320 #define HGLOBAL_STORAGE      8  /* sizeof(HGLOBAL)*2 */
321
322 typedef struct __GLOBAL32_INTERN
323 {
324    WORD         Magic;
325    LPVOID       Pointer WINE_PACKED;
326    BYTE         Flags;
327    BYTE         LockCount;
328 } GLOBAL32_INTERN, *PGLOBAL32_INTERN;
329
330
331 /***********************************************************************
332  *           GlobalAlloc   (KERNEL32.@)
333  * RETURNS
334  *      Handle: Success
335  *      NULL: Failure
336  */
337 HGLOBAL WINAPI GlobalAlloc(
338                  UINT flags, /* [in] Object allocation attributes */
339                  SIZE_T size /* [in] Number of bytes to allocate */
340 ) {
341    PGLOBAL32_INTERN     pintern;
342    DWORD                hpflags;
343    LPVOID               palloc;
344
345    if(flags&GMEM_ZEROINIT)
346       hpflags=HEAP_ZERO_MEMORY;
347    else
348       hpflags=0;
349
350    TRACE("() flags=%04x\n",  flags );
351
352    if((flags & GMEM_MOVEABLE)==0) /* POINTER */
353    {
354       palloc=HeapAlloc(GetProcessHeap(), hpflags, size);
355       return (HGLOBAL) palloc;
356    }
357    else  /* HANDLE */
358    {
359       RtlLockHeap(GetProcessHeap());
360
361       pintern = HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN));
362       if (pintern)
363       {
364           pintern->Magic = MAGIC_GLOBAL_USED;
365           pintern->Flags = flags >> 8;
366           pintern->LockCount = 0;
367
368           if (size)
369           {
370               palloc = HeapAlloc(GetProcessHeap(), hpflags, size+HGLOBAL_STORAGE);
371               if (!palloc)
372               {
373                   HeapFree(GetProcessHeap(), 0, pintern);
374                   pintern = NULL;
375               }
376               else
377               {
378                   *(HGLOBAL *)palloc = INTERN_TO_HANDLE(pintern);
379                   pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE;
380               }
381           }
382           else
383               pintern->Pointer = NULL;
384       }
385
386       RtlUnlockHeap(GetProcessHeap());
387       return pintern ? INTERN_TO_HANDLE(pintern) : 0;
388    }
389 }
390
391
392 /***********************************************************************
393  *           GlobalLock   (KERNEL32.@)
394  * RETURNS
395  *      Pointer to first byte of block
396  *      NULL: Failure
397  */
398 LPVOID WINAPI GlobalLock(
399               HGLOBAL hmem /* [in] Handle of global memory object */
400 )
401 {
402     PGLOBAL32_INTERN pintern;
403     LPVOID           palloc;
404
405     if (ISPOINTER(hmem))
406         return IsBadReadPtr(hmem, 1) ? NULL : hmem;
407
408     RtlLockHeap(GetProcessHeap());
409     __TRY
410     {
411         pintern = HANDLE_TO_INTERN(hmem);
412         if (pintern->Magic == MAGIC_GLOBAL_USED)
413         {
414             if (pintern->LockCount < GLOBAL_LOCK_MAX)
415                 pintern->LockCount++;
416             palloc = pintern->Pointer;
417         }
418         else
419         {
420             WARN("invalid handle %p\n", hmem);
421             palloc = NULL;
422             SetLastError(ERROR_INVALID_HANDLE);
423         }
424     }
425     __EXCEPT(page_fault)
426     {
427         WARN("page fault on %p\n", hmem);
428         palloc = NULL;
429         SetLastError(ERROR_INVALID_HANDLE);
430     }
431     __ENDTRY
432     RtlUnlockHeap(GetProcessHeap());
433     return palloc;
434 }
435
436
437 /***********************************************************************
438  *           GlobalUnlock   (KERNEL32.@)
439  * RETURNS
440  *      TRUE: Object is still locked
441  *      FALSE: Object is unlocked
442  */
443 BOOL WINAPI GlobalUnlock(
444               HGLOBAL hmem /* [in] Handle of global memory object */
445 ) {
446     PGLOBAL32_INTERN pintern;
447     BOOL locked;
448
449     if (ISPOINTER(hmem)) return FALSE;
450
451     RtlLockHeap(GetProcessHeap());
452     __TRY
453     {
454         pintern=HANDLE_TO_INTERN(hmem);
455         if(pintern->Magic==MAGIC_GLOBAL_USED)
456         {
457             if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
458                 pintern->LockCount--;
459
460             locked = (pintern->LockCount != 0);
461             if (!locked) SetLastError(NO_ERROR);
462         }
463         else
464         {
465             WARN("invalid handle\n");
466             SetLastError(ERROR_INVALID_HANDLE);
467             locked=FALSE;
468         }
469     }
470     __EXCEPT(page_fault)
471     {
472         ERR("page fault occurred ! Caused by bug ?\n");
473         SetLastError( ERROR_INVALID_PARAMETER );
474         locked=FALSE;
475     }
476     __ENDTRY
477     RtlUnlockHeap(GetProcessHeap());
478     return locked;
479 }
480
481
482 /***********************************************************************
483  *           GlobalHandle   (KERNEL32.@)
484  * Returns the handle associated with the specified pointer.
485  *
486  * RETURNS
487  *      Handle: Success
488  *      NULL: Failure
489  */
490 HGLOBAL WINAPI GlobalHandle(
491                  LPCVOID pmem /* [in] Pointer to global memory block */
492 ) {
493     HGLOBAL handle;
494     PGLOBAL32_INTERN  maybe_intern;
495     LPCVOID test;
496
497     if (!pmem)
498     {
499         SetLastError( ERROR_INVALID_PARAMETER );
500         return 0;
501     }
502
503     RtlLockHeap(GetProcessHeap());
504     __TRY
505     {
506         handle = 0;
507
508         /* note that if pmem is a pointer to a a block allocated by        */
509         /* GlobalAlloc with GMEM_MOVEABLE then magic test in HeapValidate  */
510         /* will fail.                                                      */
511         if (ISPOINTER(pmem)) {
512             if (HeapValidate( GetProcessHeap(), 0, pmem )) {
513                 handle = (HGLOBAL)pmem;  /* valid fixed block */
514                 break;
515             }
516             handle = POINTER_TO_HANDLE(pmem);
517         } else
518             handle = (HGLOBAL)pmem;
519
520         /* Now test handle either passed in or retrieved from pointer */
521         maybe_intern = HANDLE_TO_INTERN( handle );
522         if (maybe_intern->Magic == MAGIC_GLOBAL_USED) {
523             test = maybe_intern->Pointer;
524             if (HeapValidate( GetProcessHeap(), 0, (char *)test - HGLOBAL_STORAGE ) && /* obj(-handle) valid arena? */
525                 HeapValidate( GetProcessHeap(), 0, maybe_intern ))  /* intern valid arena? */
526                 break;  /* valid moveable block */
527         }
528         handle = 0;
529         SetLastError( ERROR_INVALID_HANDLE );
530     }
531     __EXCEPT(page_fault)
532     {
533         SetLastError( ERROR_INVALID_HANDLE );
534         handle = 0;
535     }
536     __ENDTRY
537     RtlUnlockHeap(GetProcessHeap());
538
539     return handle;
540 }
541
542
543 /***********************************************************************
544  *           GlobalReAlloc   (KERNEL32.@)
545  * RETURNS
546  *      Handle: Success
547  *      NULL: Failure
548  */
549 HGLOBAL WINAPI GlobalReAlloc(
550                  HGLOBAL hmem, /* [in] Handle of global memory object */
551                  SIZE_T size,  /* [in] New size of block */
552                  UINT flags    /* [in] How to reallocate object */
553 ) {
554    LPVOID               palloc;
555    HGLOBAL            hnew;
556    PGLOBAL32_INTERN     pintern;
557    DWORD heap_flags = (flags & GMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0;
558
559    hnew = 0;
560    RtlLockHeap(GetProcessHeap());
561    if(flags & GMEM_MODIFY) /* modify flags */
562    {
563       if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
564       {
565          /* make a fixed block moveable
566           * actually only NT is able to do this. But it's soo simple
567           */
568          if (hmem == 0)
569          {
570              WARN("GlobalReAlloc with null handle!\n");
571              SetLastError( ERROR_NOACCESS );
572              hnew = 0;
573          }
574          else
575          {
576              size = HeapSize(GetProcessHeap(), 0, (LPVOID)hmem);
577              hnew = GlobalAlloc(flags, size);
578              palloc = GlobalLock(hnew);
579              memcpy(palloc, (LPVOID)hmem, size);
580              GlobalUnlock(hnew);
581              GlobalFree(hmem);
582          }
583       }
584       else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
585       {
586          /* change the flags to make our block "discardable" */
587          pintern=HANDLE_TO_INTERN(hmem);
588          pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8);
589          hnew=hmem;
590       }
591       else
592       {
593          SetLastError(ERROR_INVALID_PARAMETER);
594          hnew = 0;
595       }
596    }
597    else
598    {
599       if(ISPOINTER(hmem))
600       {
601          /* reallocate fixed memory */
602          hnew=(HGLOBAL)HeapReAlloc(GetProcessHeap(), heap_flags, (LPVOID) hmem, size);
603       }
604       else
605       {
606          /* reallocate a moveable block */
607          pintern=HANDLE_TO_INTERN(hmem);
608
609 #if 0
610 /* Apparently Windows doesn't care whether the handle is locked at this point */
611 /* See also the same comment in GlobalFree() */
612          if(pintern->LockCount>1) {
613             ERR("handle 0x%08lx is still locked, cannot realloc!\n",(DWORD)hmem);
614             SetLastError(ERROR_INVALID_HANDLE);
615          } else
616 #endif
617          if(size!=0)
618          {
619             hnew=hmem;
620             if(pintern->Pointer)
621             {
622                if((palloc = HeapReAlloc(GetProcessHeap(), heap_flags,
623                                    (char *) pintern->Pointer-HGLOBAL_STORAGE,
624                                    size+HGLOBAL_STORAGE)) == NULL)
625                    hnew = 0; /* Block still valid */
626                else
627                    pintern->Pointer = (char *)palloc+HGLOBAL_STORAGE;
628             }
629             else
630             {
631                 if((palloc=HeapAlloc(GetProcessHeap(), heap_flags, size+HGLOBAL_STORAGE))
632                    == NULL)
633                     hnew = 0;
634                 else
635                 {
636                     *(HGLOBAL *)palloc = hmem;
637                     pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE;
638                 }
639             }
640          }
641          else
642          {
643             if(pintern->Pointer)
644             {
645                HeapFree(GetProcessHeap(), 0, (char *) pintern->Pointer-HGLOBAL_STORAGE);
646                pintern->Pointer=NULL;
647             }
648          }
649       }
650    }
651    RtlUnlockHeap(GetProcessHeap());
652    return hnew;
653 }
654
655
656 /***********************************************************************
657  *           GlobalFree   (KERNEL32.@)
658  * RETURNS
659  *      NULL: Success
660  *      Handle: Failure
661  */
662 HGLOBAL WINAPI GlobalFree(
663                  HGLOBAL hmem /* [in] Handle of global memory object */
664 ) {
665     PGLOBAL32_INTERN pintern;
666     HGLOBAL hreturned;
667
668     RtlLockHeap(GetProcessHeap());
669     __TRY
670     {
671         hreturned = 0;
672         if(ISPOINTER(hmem)) /* POINTER */
673         {
674             if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem)) hmem = 0;
675         }
676         else  /* HANDLE */
677         {
678             pintern=HANDLE_TO_INTERN(hmem);
679
680             if(pintern->Magic==MAGIC_GLOBAL_USED)
681             {
682
683                 /* WIN98 does not make this test. That is you can free a */
684                 /* block you have not unlocked. Go figure!!              */
685                 /* if(pintern->LockCount!=0)  */
686                 /*    SetLastError(ERROR_INVALID_HANDLE);  */
687
688                 if(pintern->Pointer)
689                     if(!HeapFree(GetProcessHeap(), 0, (char *)(pintern->Pointer)-HGLOBAL_STORAGE))
690                         hreturned=hmem;
691                 if(!HeapFree(GetProcessHeap(), 0, pintern))
692                     hreturned=hmem;
693             }
694         }
695     }
696     __EXCEPT(page_fault)
697     {
698         ERR("page fault occurred ! Caused by bug ?\n");
699         SetLastError( ERROR_INVALID_PARAMETER );
700         hreturned = hmem;
701     }
702     __ENDTRY
703     RtlUnlockHeap(GetProcessHeap());
704     return hreturned;
705 }
706
707
708 /***********************************************************************
709  *           GlobalSize   (KERNEL32.@)
710  * RETURNS
711  *      Size in bytes of the global memory object
712  *      0: Failure
713  */
714 SIZE_T WINAPI GlobalSize(
715              HGLOBAL hmem /* [in] Handle of global memory object */
716 ) {
717    DWORD                retval;
718    PGLOBAL32_INTERN     pintern;
719
720    if (!hmem) return 0;
721
722    if(ISPOINTER(hmem))
723    {
724       retval=HeapSize(GetProcessHeap(), 0,  (LPVOID) hmem);
725    }
726    else
727    {
728       RtlLockHeap(GetProcessHeap());
729       pintern=HANDLE_TO_INTERN(hmem);
730
731       if(pintern->Magic==MAGIC_GLOBAL_USED)
732       {
733          if (!pintern->Pointer) /* handle case of GlobalAlloc( ??,0) */
734              retval = 0;
735          else
736          {
737              retval = HeapSize(GetProcessHeap(), 0,
738                          (char *)(pintern->Pointer) - HGLOBAL_STORAGE );
739              if (retval != (DWORD)-1) retval -= HGLOBAL_STORAGE;
740          }
741       }
742       else
743       {
744          WARN("invalid handle\n");
745          retval=0;
746       }
747       RtlUnlockHeap(GetProcessHeap());
748    }
749    /* HeapSize returns 0xffffffff on failure */
750    if (retval == 0xffffffff) retval = 0;
751    return retval;
752 }
753
754
755 /***********************************************************************
756  *           GlobalWire   (KERNEL32.@)
757  */
758 LPVOID WINAPI GlobalWire(HGLOBAL hmem)
759 {
760    return GlobalLock( hmem );
761 }
762
763
764 /***********************************************************************
765  *           GlobalUnWire   (KERNEL32.@)
766  */
767 BOOL WINAPI GlobalUnWire(HGLOBAL hmem)
768 {
769    return GlobalUnlock( hmem);
770 }
771
772
773 /***********************************************************************
774  *           GlobalFix   (KERNEL32.@)
775  */
776 VOID WINAPI GlobalFix(HGLOBAL hmem)
777 {
778     GlobalLock( hmem );
779 }
780
781
782 /***********************************************************************
783  *           GlobalUnfix   (KERNEL32.@)
784  */
785 VOID WINAPI GlobalUnfix(HGLOBAL hmem)
786 {
787    GlobalUnlock( hmem);
788 }
789
790
791 /***********************************************************************
792  *           GlobalFlags   (KERNEL32.@)
793  * Returns information about the specified global memory object
794  *
795  * NOTES
796  *      Should this return GMEM_INVALID_HANDLE on invalid handle?
797  *
798  * RETURNS
799  *      Value specifying allocation flags and lock count
800  *      GMEM_INVALID_HANDLE: Failure
801  */
802 UINT WINAPI GlobalFlags(
803               HGLOBAL hmem /* [in] Handle to global memory object */
804 ) {
805    DWORD                retval;
806    PGLOBAL32_INTERN     pintern;
807
808    if(ISPOINTER(hmem))
809    {
810       retval=0;
811    }
812    else
813    {
814       RtlLockHeap(GetProcessHeap());
815       pintern=HANDLE_TO_INTERN(hmem);
816       if(pintern->Magic==MAGIC_GLOBAL_USED)
817       {
818          retval=pintern->LockCount + (pintern->Flags<<8);
819          if(pintern->Pointer==0)
820             retval|= GMEM_DISCARDED;
821       }
822       else
823       {
824          WARN("Invalid handle: %p\n", hmem);
825          retval=0;
826       }
827       RtlUnlockHeap(GetProcessHeap());
828    }
829    return retval;
830 }
831
832
833 /***********************************************************************
834  *           GlobalCompact   (KERNEL32.@)
835  */
836 SIZE_T WINAPI GlobalCompact( DWORD minfree )
837 {
838     return 0;  /* GlobalCompact does nothing in Win32 */
839 }
840
841
842 /***********************************************************************
843  *           LocalAlloc   (KERNEL32.@)
844  * RETURNS
845  *      Handle: Success
846  *      NULL: Failure
847  */
848 HLOCAL WINAPI LocalAlloc(
849                 UINT flags, /* [in] Allocation attributes */
850                 SIZE_T size /* [in] Number of bytes to allocate */
851 ) {
852     return (HLOCAL)GlobalAlloc( flags, size );
853 }
854
855
856 /***********************************************************************
857  *           LocalCompact   (KERNEL32.@)
858  */
859 SIZE_T WINAPI LocalCompact( UINT minfree )
860 {
861     return 0;  /* LocalCompact does nothing in Win32 */
862 }
863
864
865 /***********************************************************************
866  *           LocalFlags   (KERNEL32.@)
867  * RETURNS
868  *      Value specifying allocation flags and lock count.
869  *      LMEM_INVALID_HANDLE: Failure
870  */
871 UINT WINAPI LocalFlags(
872               HLOCAL handle /* [in] Handle of memory object */
873 ) {
874     return GlobalFlags( (HGLOBAL)handle );
875 }
876
877
878 /***********************************************************************
879  *           LocalFree   (KERNEL32.@)
880  * RETURNS
881  *      NULL: Success
882  *      Handle: Failure
883  */
884 HLOCAL WINAPI LocalFree(
885                 HLOCAL handle /* [in] Handle of memory object */
886 ) {
887     return (HLOCAL)GlobalFree( (HGLOBAL)handle );
888 }
889
890
891 /***********************************************************************
892  *           LocalHandle   (KERNEL32.@)
893  * RETURNS
894  *      Handle: Success
895  *      NULL: Failure
896  */
897 HLOCAL WINAPI LocalHandle(
898                 LPCVOID ptr /* [in] Address of local memory object */
899 ) {
900     return (HLOCAL)GlobalHandle( ptr );
901 }
902
903
904 /***********************************************************************
905  *           LocalLock   (KERNEL32.@)
906  * Locks a local memory object and returns pointer to the first byte
907  * of the memory block.
908  *
909  * RETURNS
910  *      Pointer: Success
911  *      NULL: Failure
912  */
913 LPVOID WINAPI LocalLock(
914               HLOCAL handle /* [in] Address of local memory object */
915 ) {
916     return GlobalLock( (HGLOBAL)handle );
917 }
918
919
920 /***********************************************************************
921  *           LocalReAlloc   (KERNEL32.@)
922  * RETURNS
923  *      Handle: Success
924  *      NULL: Failure
925  */
926 HLOCAL WINAPI LocalReAlloc(
927                 HLOCAL handle, /* [in] Handle of memory object */
928                 SIZE_T size,   /* [in] New size of block */
929                 UINT flags     /* [in] How to reallocate object */
930 ) {
931     return (HLOCAL)GlobalReAlloc( (HGLOBAL)handle, size, flags );
932 }
933
934
935 /***********************************************************************
936  *           LocalShrink   (KERNEL32.@)
937  */
938 SIZE_T WINAPI LocalShrink( HGLOBAL handle, UINT newsize )
939 {
940     return 0;  /* LocalShrink does nothing in Win32 */
941 }
942
943
944 /***********************************************************************
945  *           LocalSize   (KERNEL32.@)
946  * RETURNS
947  *      Size: Success
948  *      0: Failure
949  */
950 SIZE_T WINAPI LocalSize(
951               HLOCAL handle /* [in] Handle of memory object */
952 ) {
953     return GlobalSize( (HGLOBAL)handle );
954 }
955
956
957 /***********************************************************************
958  *           LocalUnlock   (KERNEL32.@)
959  * RETURNS
960  *      TRUE: Object is still locked
961  *      FALSE: Object is unlocked
962  */
963 BOOL WINAPI LocalUnlock(
964               HLOCAL handle /* [in] Handle of memory object */
965 ) {
966     return GlobalUnlock( (HGLOBAL)handle );
967 }
968
969
970 /**********************************************************************
971  *              AllocMappedBuffer       (KERNEL32.38)
972  *
973  * This is a undocumented KERNEL32 function that
974  * SMapLS's a GlobalAlloc'ed buffer.
975  *
976  * Input:   EDI register: size of buffer to allocate
977  * Output:  EDI register: pointer to buffer
978  *
979  * Note: The buffer is preceded by 8 bytes:
980  *        ...
981  *       edi+0   buffer
982  *       edi-4   SEGPTR to buffer
983  *       edi-8   some magic Win95 needs for SUnMapLS
984  *               (we use it for the memory handle)
985  *
986  *       The SEGPTR is used by the caller!
987  */
988 void WINAPI AllocMappedBuffer( CONTEXT86 *context )
989 {
990     HGLOBAL handle = GlobalAlloc(0, context->Edi + 8);
991     DWORD *buffer = (DWORD *)GlobalLock(handle);
992     DWORD ptr = 0;
993
994     if (buffer)
995         if (!(ptr = MapLS(buffer + 2)))
996         {
997             GlobalUnlock(handle);
998             GlobalFree(handle);
999         }
1000
1001     if (!ptr)
1002         context->Eax = context->Edi = 0;
1003     else
1004     {
1005         buffer[0] = (DWORD)handle;
1006         buffer[1] = ptr;
1007
1008         context->Eax = (DWORD) ptr;
1009         context->Edi = (DWORD)(buffer + 2);
1010     }
1011 }
1012
1013
1014 /**********************************************************************
1015  *              FreeMappedBuffer        (KERNEL32.39)
1016  *
1017  * Free a buffer allocated by AllocMappedBuffer
1018  *
1019  * Input: EDI register: pointer to buffer
1020  */
1021 void WINAPI FreeMappedBuffer( CONTEXT86 *context )
1022 {
1023     if (context->Edi)
1024     {
1025         DWORD *buffer = (DWORD *)context->Edi - 2;
1026
1027         UnMapLS(buffer[1]);
1028
1029         GlobalUnlock((HGLOBAL)buffer[0]);
1030         GlobalFree((HGLOBAL)buffer[0]);
1031     }
1032 }
1033
1034 /***********************************************************************
1035  *           GlobalMemoryStatus   (KERNEL32.@)
1036  * Provides information about the status of the memory, so apps can tell
1037  * roughly how much they are able to allocate
1038  *
1039  * RETURNS
1040  *      None
1041  */
1042 VOID WINAPI GlobalMemoryStatus(
1043             LPMEMORYSTATUS lpmem
1044 ) {
1045     static MEMORYSTATUS cached_memstatus;
1046     static int cache_lastchecked = 0;
1047     SYSTEM_INFO si;
1048 #ifdef linux
1049     FILE *f;
1050 #endif
1051 #if defined(__FreeBSD__) || defined(__NetBSD__)
1052     int *tmp;
1053     int size_sys;
1054     int mib[2] = { CTL_HW };
1055 #endif
1056     if (time(NULL)==cache_lastchecked) {
1057         memcpy(lpmem,&cached_memstatus,sizeof(MEMORYSTATUS));
1058         return;
1059     }
1060     cache_lastchecked = time(NULL);
1061
1062     lpmem->dwMemoryLoad    = 0;
1063     lpmem->dwTotalPhys     = 16*1024*1024;
1064     lpmem->dwAvailPhys     = 16*1024*1024;
1065     lpmem->dwTotalPageFile = 16*1024*1024;
1066     lpmem->dwAvailPageFile = 16*1024*1024;
1067
1068 #ifdef linux
1069     f = fopen( "/proc/meminfo", "r" );
1070     if (f)
1071     {
1072         char buffer[256];
1073         int total, used, free, shared, buffers, cached;
1074
1075         lpmem->dwLength = sizeof(MEMORYSTATUS);
1076         lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
1077         lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
1078         while (fgets( buffer, sizeof(buffer), f ))
1079         {
1080             /* old style /proc/meminfo ... */
1081             if (sscanf( buffer, "Mem: %d %d %d %d %d %d", &total, &used, &free, &shared, &buffers, &cached ))
1082             {
1083                 lpmem->dwTotalPhys += total;
1084                 lpmem->dwAvailPhys += free + buffers + cached;
1085             }
1086             if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
1087             {
1088                 lpmem->dwTotalPageFile += total;
1089                 lpmem->dwAvailPageFile += free;
1090             }
1091
1092             /* new style /proc/meminfo ... */
1093             if (sscanf(buffer, "MemTotal: %d", &total))
1094                 lpmem->dwTotalPhys = total*1024;
1095             if (sscanf(buffer, "MemFree: %d", &free))
1096                 lpmem->dwAvailPhys = free*1024;
1097             if (sscanf(buffer, "SwapTotal: %d", &total))
1098                 lpmem->dwTotalPageFile = total*1024;
1099             if (sscanf(buffer, "SwapFree: %d", &free))
1100                 lpmem->dwAvailPageFile = free*1024;
1101             if (sscanf(buffer, "Buffers: %d", &buffers))
1102                 lpmem->dwAvailPhys += buffers*1024;
1103             if (sscanf(buffer, "Cached: %d", &cached))
1104                 lpmem->dwAvailPhys += cached*1024;
1105         }
1106         fclose( f );
1107
1108         if (lpmem->dwTotalPhys)
1109         {
1110             DWORD TotalPhysical = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
1111             DWORD AvailPhysical = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
1112             lpmem->dwMemoryLoad = (TotalPhysical-AvailPhysical)
1113                                       / (TotalPhysical / 100);
1114         }
1115     }
1116 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1117     mib[1] = HW_PHYSMEM;
1118     sysctl(mib, 2, NULL, &size_sys, NULL, 0);
1119     tmp = malloc(size_sys * sizeof(int));
1120     sysctl(mib, 2, tmp, &size_sys, NULL, 0);
1121     if (tmp && *tmp)
1122     {
1123         lpmem->dwTotalPhys = *tmp;
1124         free(tmp);
1125         mib[1] = HW_USERMEM;
1126         sysctl(mib, 2, NULL, &size_sys, NULL, 0);
1127         tmp = malloc(size_sys * sizeof(int));
1128         sysctl(mib, 2, tmp, &size_sys, NULL, 0);
1129         if (tmp && *tmp)
1130         {
1131             lpmem->dwAvailPhys = *tmp;
1132             lpmem->dwTotalPageFile = *tmp;
1133             lpmem->dwAvailPageFile = *tmp;
1134             lpmem->dwMemoryLoad = lpmem->dwTotalPhys - lpmem->dwAvailPhys;
1135         } else
1136         {
1137             lpmem->dwAvailPhys = lpmem->dwTotalPhys;
1138             lpmem->dwTotalPageFile = lpmem->dwTotalPhys;
1139             lpmem->dwAvailPageFile = lpmem->dwTotalPhys;
1140             lpmem->dwMemoryLoad = 0;
1141         }
1142         free(tmp);
1143
1144     }
1145 #endif
1146     /* Some applications (e.g. QuickTime 6) crash if we tell them there
1147      * is more than 2GB of physical memory.
1148      */
1149     if (lpmem->dwTotalPhys>2U*1024*1024*1024)
1150     {
1151         lpmem->dwTotalPhys=2U*1024*1024*1024;
1152         lpmem->dwAvailPhys=2U*1024*1024*1024;
1153     }
1154
1155     /* FIXME: should do something for other systems */
1156     GetSystemInfo(&si);
1157     lpmem->dwTotalVirtual  = (char*)si.lpMaximumApplicationAddress-(char*)si.lpMinimumApplicationAddress;
1158     /* FIXME: we should track down all the already allocated VM pages and substract them, for now arbitrarily remove 64KB so that it matches NT */
1159     lpmem->dwAvailVirtual  = lpmem->dwTotalVirtual-64*1024;
1160     memcpy(&cached_memstatus,lpmem,sizeof(MEMORYSTATUS));
1161
1162     /* it appears some memory display programs want to divide by these values */
1163     if(lpmem->dwTotalPageFile==0)
1164         lpmem->dwTotalPageFile++;
1165
1166     if(lpmem->dwAvailPageFile==0)
1167         lpmem->dwAvailPageFile++;
1168
1169     TRACE("<-- LPMEMORYSTATUS: dwLength %ld, dwMemoryLoad %ld, dwTotalPhys %ld, dwAvailPhys %ld,"
1170           " dwTotalPageFile %ld, dwAvailPageFile %ld, dwTotalVirtual %ld, dwAvailVirtual %ld\n",
1171           lpmem->dwLength, lpmem->dwMemoryLoad, lpmem->dwTotalPhys, lpmem->dwAvailPhys,
1172           lpmem->dwTotalPageFile, lpmem->dwAvailPageFile, lpmem->dwTotalVirtual,
1173           lpmem->dwAvailVirtual);
1174 }
1175
1176 /***********************************************************************
1177  *           GlobalMemoryStatusEx   (KERNEL32.@)
1178  * A version of GlobalMemoryStatus that can deal with memory over 4GB
1179  *
1180  * RETURNS
1181  *      None
1182  */
1183 BOOL WINAPI GlobalMemoryStatusEx( LPMEMORYSTATUSEX lpBuffer )
1184 {
1185   MEMORYSTATUS memstatus;
1186
1187   /* Because GlobalMemoryStatusEx is identical to GlobalMemoryStatus save
1188      for one extra field in the struct, and the lack of a bug, we simply
1189      call GlobalMemoryStatus and copy the values across. */
1190   FIXME("we should emulate the 4GB bug here, as per MSDN\n");
1191   GlobalMemoryStatus(&memstatus);
1192   lpBuffer->dwMemoryLoad = memstatus.dwMemoryLoad;
1193   lpBuffer->ullTotalPhys = memstatus.dwTotalPhys;
1194   lpBuffer->ullAvailPhys = memstatus.dwAvailPhys;
1195   lpBuffer->ullTotalPageFile = memstatus.dwTotalPageFile;
1196   lpBuffer->ullAvailPageFile = memstatus.dwAvailPageFile;
1197   lpBuffer->ullTotalVirtual = memstatus.dwTotalVirtual;
1198   lpBuffer->ullAvailVirtual = memstatus.dwAvailVirtual;
1199   /* MSDN says about AvailExtendedVirtual: Size of unreserved and uncommitted
1200      memory in the extended portion of the virtual address space of the calling
1201      process, in bytes.
1202      However, I don't know what this means, so set it to zero :(
1203   */
1204   lpBuffer->ullAvailExtendedVirtual = 0;
1205   return 1;
1206 }