xref: /reactos/dll/win32/kernel32/client/heapmem.c (revision d0907262)
1 /*
2  * PROJECT:         ReactOS Win32 Base API
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            dll/win32/kernel32/client/heapmem.c
5  * PURPOSE:         Heap Memory APIs (wrappers for RtlHeap*)
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <k32.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
18 RTL_HANDLE_TABLE BaseHeapHandleTable;
19 HANDLE BaseHeap;
20 ULONG_PTR SystemRangeStart;
21 
22 /* PRIVATE FUNCTIONS **********************************************************/
23 
24 VOID
25 NTAPI
BaseDllInitializeMemoryManager(VOID)26 BaseDllInitializeMemoryManager(VOID)
27 {
28     BaseHeap = RtlGetProcessHeap();
29     RtlInitializeHandleTable(0xFFFF,
30                              sizeof(BASE_HEAP_HANDLE_ENTRY),
31                              &BaseHeapHandleTable);
32     NtQuerySystemInformation(SystemRangeStartInformation,
33                              &SystemRangeStart,
34                              sizeof(SystemRangeStart),
35                              NULL);
36 }
37 
38 /* PUBLIC FUNCTIONS ***********************************************************/
39 
40 /*
41  * @implemented
42  */
43 HANDLE
44 WINAPI
HeapCreate(DWORD flOptions,SIZE_T dwInitialSize,SIZE_T dwMaximumSize)45 HeapCreate(DWORD flOptions,
46            SIZE_T dwInitialSize,
47            SIZE_T dwMaximumSize)
48 {
49     HANDLE hRet;
50     ULONG Flags;
51 
52     /* Remove non-Win32 flags and tag this allocation */
53     Flags = (flOptions & (HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE)) |
54             HEAP_CLASS_1;
55 
56     /* Check if heap is growable and ensure max size is correct */
57     if (dwMaximumSize == 0)
58         Flags |= HEAP_GROWABLE;
59     else if (dwMaximumSize < BaseStaticServerData->SysInfo.PageSize &&
60             dwInitialSize > dwMaximumSize)
61     {
62         /* Max size is non-zero but less than page size which can't be correct.
63            Fix it up by bumping it to the initial size whatever it is. */
64         dwMaximumSize = dwInitialSize;
65     }
66 
67     /* Call RTL Heap */
68     hRet = RtlCreateHeap(Flags,
69                          NULL,
70                          dwMaximumSize,
71                          dwInitialSize,
72                          NULL,
73                          NULL);
74 
75     /* Set the last error if we failed, and return the pointer */
76     if (!hRet) SetLastError(ERROR_NOT_ENOUGH_MEMORY);
77     return hRet;
78 }
79 
80 /*
81  * @implemented
82  */
83 BOOL
84 WINAPI
HeapDestroy(HANDLE hHeap)85 HeapDestroy(HANDLE hHeap)
86 {
87     /* Return TRUE if the heap was destroyed */
88    if (!RtlDestroyHeap(hHeap)) return TRUE;
89 
90     /* Otherwise, we got the handle back, so fail */
91     SetLastError(ERROR_INVALID_HANDLE);
92     return FALSE;
93 }
94 
95 /*
96  * @implemented
97  */
98 HANDLE
99 WINAPI
GetProcessHeap(VOID)100 GetProcessHeap(VOID)
101 {
102     /* Call the RTL API */
103     return RtlGetProcessHeap();
104 }
105 
106 /*
107  * @implemented
108  */
109 DWORD
110 WINAPI
GetProcessHeaps(DWORD NumberOfHeaps,PHANDLE ProcessHeaps)111 GetProcessHeaps(DWORD NumberOfHeaps,
112                 PHANDLE ProcessHeaps)
113 {
114     /* Call the RTL API */
115     return RtlGetProcessHeaps(NumberOfHeaps, ProcessHeaps);
116 }
117 
118 /*
119  * @implemented
120  */
121 BOOL
122 WINAPI
HeapLock(HANDLE hHeap)123 HeapLock(HANDLE hHeap)
124 {
125     /* Call the RTL API */
126     return RtlLockHeap(hHeap);
127 }
128 
129 /*
130  * @implemented
131  */
132 BOOL
133 WINAPI
HeapUnlock(HANDLE hHeap)134 HeapUnlock(HANDLE hHeap)
135 {
136     /* Call the RTL API */
137     return RtlUnlockHeap(hHeap);
138 }
139 
140 /*
141  * @implemented
142  */
143 SIZE_T
144 WINAPI
HeapCompact(HANDLE hHeap,DWORD dwFlags)145 HeapCompact(HANDLE hHeap, DWORD dwFlags)
146 {
147     /* Call the RTL API */
148     return RtlCompactHeap(hHeap, dwFlags);
149 }
150 
151 /*
152  * @implemented
153  */
154 BOOL
155 WINAPI
HeapValidate(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem)156 HeapValidate(HANDLE hHeap,
157              DWORD dwFlags,
158              LPCVOID lpMem)
159 {
160     /* Call the RTL API */
161     return RtlValidateHeap(hHeap, dwFlags, (PVOID)lpMem);
162 }
163 
164 /*
165  * @implemented
166  */
167 DWORD
168 WINAPI
HeapCreateTagsW(_In_ HANDLE hHeap,_In_ DWORD dwFlags,_In_opt_ PWSTR lpTagName,_In_ PWSTR lpTagSubName)169 HeapCreateTagsW(_In_ HANDLE hHeap,
170                 _In_ DWORD dwFlags,
171                 _In_opt_ PWSTR lpTagName,
172                 _In_ PWSTR lpTagSubName)
173 {
174     /* Call the RTL API */
175     return RtlCreateTagHeap(hHeap,
176                             dwFlags,
177                             lpTagName,
178                             lpTagSubName);
179 }
180 
181 /*
182  * @implemented
183  */
184 DWORD
185 WINAPI
HeapExtend(HANDLE hHeap,DWORD dwFlags,PVOID BaseAddress,DWORD dwBytes)186 HeapExtend(HANDLE hHeap,
187            DWORD dwFlags,
188            PVOID BaseAddress,
189            DWORD dwBytes)
190 {
191     NTSTATUS Status;
192 
193     /* Call the RTL API. Gone in Vista, so commented out. */
194     Status = STATUS_NOT_IMPLEMENTED; //RtlExtendHeap(hHeap, dwFlags, BaseAddress, dwBytes);
195     if (!NT_SUCCESS(Status))
196     {
197         /* We failed */
198         BaseSetLastNTError(Status);
199         return FALSE;
200     }
201 
202     /* Return success */
203     return TRUE;
204 }
205 
206 /*
207  * @implemented
208  */
209 PWSTR
210 WINAPI
HeapQueryTagW(HANDLE hHeap,DWORD dwFlags,WORD wTagIndex,BOOL bResetCounters,PVOID lpTagInfo)211 HeapQueryTagW(HANDLE hHeap,
212               DWORD dwFlags,
213               WORD wTagIndex,
214               BOOL bResetCounters,
215               PVOID lpTagInfo)
216 {
217     /* Call the RTL API */
218     return RtlQueryTagHeap(hHeap,
219                            dwFlags,
220                            wTagIndex,
221                            (BOOLEAN)bResetCounters,
222                            lpTagInfo);
223 }
224 
225 /*
226  * @implemented
227  */
228 BOOL
229 WINAPI
HeapSummary(HANDLE hHeap,DWORD dwFlags,PVOID Summary)230 HeapSummary(HANDLE hHeap,
231             DWORD dwFlags,
232             PVOID Summary)
233 {
234     NTSTATUS Status;
235     RTL_HEAP_USAGE Usage;
236 
237     /* Fill in the length information */
238     Usage.Length = sizeof(Usage);
239 
240     /* Call RTL. Gone in Vista, so commented out */
241     Status = STATUS_NOT_IMPLEMENTED; //RtlUsageHeap(hHeap, dwFlags, &Usage);
242     if (!NT_SUCCESS(Status))
243     {
244         /* We failed */
245         BaseSetLastNTError(Status);
246         return FALSE;
247     }
248 
249     /* FIXME: Summary == Usage?! */
250     RtlCopyMemory(Summary, &Usage, sizeof(Usage));
251     return TRUE;
252 }
253 
254 /*
255  * @implemented
256  */
257 BOOL
258 WINAPI
HeapUsage(HANDLE hHeap,DWORD dwFlags,DWORD Unknown,DWORD Unknown2,IN PVOID Usage)259 HeapUsage(HANDLE hHeap,
260           DWORD dwFlags,
261           DWORD Unknown,
262           DWORD Unknown2,
263           IN PVOID Usage)
264 {
265     NTSTATUS Status;
266 
267     /* Call RTL. Gone in Vista, so commented out */
268     Status = STATUS_NOT_IMPLEMENTED; //RtlUsageHeap(hHeap, dwFlags, &Usage);
269     if (!NT_SUCCESS(Status))
270     {
271         /* We failed */
272         BaseSetLastNTError(Status);
273         return FALSE;
274     }
275     else if (Status == STATUS_MORE_ENTRIES)
276     {
277         /* There are still more entries to parse */
278         return TRUE;
279     }
280 
281     /* Otherwise, we're completely done, so we return FALSE, but NO_ERROR */
282     SetLastError(NO_ERROR);
283     return FALSE;
284 }
285 
286 /*
287  * @implemented
288  */
289 BOOL
290 WINAPI
HeapWalk(HANDLE hHeap,LPPROCESS_HEAP_ENTRY lpEntry)291 HeapWalk(HANDLE	hHeap,
292          LPPROCESS_HEAP_ENTRY lpEntry)
293 {
294     NTSTATUS Status;
295 
296     DPRINT1("Warning, HeapWalk is calling RtlWalkHeap with Win32 parameters\n");
297 
298     Status = RtlWalkHeap(hHeap, lpEntry);
299 
300     if (!NT_SUCCESS(Status))
301     {
302         SetLastError(RtlNtStatusToDosError(Status));
303         return FALSE;
304     }
305 
306     return TRUE;
307 }
308 
309 /*
310  * @implemented
311  */
312 BOOL
313 WINAPI
HeapQueryInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation OPTIONAL,SIZE_T HeapInformationLength OPTIONAL,PSIZE_T ReturnLength OPTIONAL)314 HeapQueryInformation(HANDLE HeapHandle,
315                      HEAP_INFORMATION_CLASS HeapInformationClass,
316                      PVOID HeapInformation OPTIONAL,
317                      SIZE_T HeapInformationLength OPTIONAL,
318                      PSIZE_T ReturnLength OPTIONAL)
319 {
320     NTSTATUS Status;
321 
322     Status = RtlQueryHeapInformation(HeapHandle,
323                                      HeapInformationClass,
324                                      HeapInformation,
325                                      HeapInformationLength,
326                                      ReturnLength);
327 
328     if (!NT_SUCCESS(Status))
329     {
330         BaseSetLastNTError(Status);
331         return FALSE;
332     }
333 
334     return TRUE;
335 }
336 
337 /*
338  * @implemented
339  */
340 BOOL
341 WINAPI
HeapSetInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation OPTIONAL,SIZE_T HeapInformationLength OPTIONAL)342 HeapSetInformation(HANDLE HeapHandle,
343                    HEAP_INFORMATION_CLASS HeapInformationClass,
344                    PVOID HeapInformation OPTIONAL,
345                    SIZE_T HeapInformationLength OPTIONAL)
346 {
347     NTSTATUS Status;
348 
349     Status = RtlSetHeapInformation(HeapHandle,
350                                    HeapInformationClass,
351                                    HeapInformation,
352                                    HeapInformationLength);
353 
354     if (!NT_SUCCESS(Status))
355     {
356         BaseSetLastNTError(Status);
357         return FALSE;
358     }
359 
360     return TRUE;
361 }
362 
363 /*
364  * @implemented
365  */
366 HGLOBAL
367 NTAPI
GlobalAlloc(UINT uFlags,SIZE_T dwBytes)368 GlobalAlloc(UINT uFlags,
369             SIZE_T dwBytes)
370 {
371     ULONG Flags = 0;
372     PVOID Ptr = NULL;
373     HANDLE hMemory;
374     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
375     BASE_TRACE_ALLOC(dwBytes, uFlags);
376     ASSERT(BaseHeap);
377 
378     /* Make sure the flags are valid */
379     if (uFlags & ~GMEM_VALID_FLAGS)
380     {
381         /* They aren't, fail */
382         BASE_TRACE_FAILURE();
383         SetLastError(ERROR_INVALID_PARAMETER);
384         return NULL;
385     }
386 
387     /* Convert ZEROINIT */
388     if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
389 
390     /* Check if we're not movable, which means pointer-based heap */
391     if (!(uFlags & GMEM_MOVEABLE))
392     {
393         /* Check if this is DDESHARE (deprecated) */
394         if (uFlags & GMEM_DDESHARE) Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
395 
396         /* Allocate heap for it */
397         Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes ? dwBytes : 1);
398         if (!Ptr) SetLastError(ERROR_NOT_ENOUGH_MEMORY);
399         BASE_TRACE_ALLOC2(Ptr);
400         return Ptr;
401     }
402 
403     /* This is heap based, so lock it in first */
404     RtlLockHeap(BaseHeap);
405 
406     /*
407      * Disable locking, enable custom flags, and write the
408      * movable flag (deprecated)
409      */
410     Flags |= HEAP_NO_SERIALIZE |
411              HEAP_SETTABLE_USER_VALUE |
412              BASE_HEAP_FLAG_MOVABLE;
413 
414     /* Allocate the handle */
415     HandleEntry = BaseHeapAllocEntry();
416     if (!HandleEntry)
417     {
418         /* Fail */
419         hMemory = NULL;
420         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
421         BASE_TRACE_FAILURE();
422     }
423     else
424     {
425         /* Get the object and make sure we have size */
426         hMemory = &HandleEntry->Object;
427         if (dwBytes)
428         {
429             /* Allocate the actual memory for it */
430             Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
431             BASE_TRACE_PTR(HandleEntry, Ptr);
432             if (!Ptr)
433             {
434                 /* We failed, manually set the allocate flag and free the handle */
435                 HandleEntry->Flags = RTL_HANDLE_VALID;
436                 BaseHeapFreeEntry(HandleEntry);
437 
438                 /* For the cleanup case */
439                 HandleEntry = NULL;
440             }
441             else
442             {
443                 /* All worked well, save our heap entry */
444                 RtlSetUserValueHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr, hMemory);
445             }
446         }
447     }
448 
449     /* Cleanup! First unlock the heap */
450     RtlUnlockHeap(BaseHeap);
451 
452     /* Check if a handle was allocated */
453     if (HandleEntry)
454     {
455         /* Set the pointer and allocated flag */
456         HandleEntry->Object = Ptr;
457         HandleEntry->Flags = RTL_HANDLE_VALID;
458         if (!Ptr)
459         {
460             /* We don't have a valid pointer, but so reuse this handle */
461             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
462         }
463 
464         /* Check if the handle is discardable */
465         if (uFlags & GMEM_DISCARDABLE)
466         {
467             /* Save it in the handle entry */
468             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
469         }
470 
471         /* Check if the handle is moveable */
472         if (uFlags & GMEM_MOVEABLE)
473         {
474             /* Save it in the handle entry */
475             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE;
476         }
477 
478         /* Check if the handle is DDE Shared */
479         if (uFlags & GMEM_DDESHARE)
480         {
481             /* Save it in the handle entry */
482             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
483         }
484 
485         /* Set the pointer */
486         Ptr = hMemory;
487     }
488 
489     /* Return the pointer */
490     return Ptr;
491 }
492 
493 /*
494  * @implemented
495  */
496 SIZE_T
497 NTAPI
GlobalCompact(DWORD dwMinFree)498 GlobalCompact(DWORD dwMinFree)
499 {
500     /* Call the RTL Heap Manager */
501     return RtlCompactHeap(BaseHeap, 0);
502 }
503 
504 /*
505  * @implemented
506  */
507 VOID
508 NTAPI
GlobalFix(HGLOBAL hMem)509 GlobalFix(HGLOBAL hMem)
510 {
511     /* Lock the memory if it the handle is valid */
512     if (INVALID_HANDLE_VALUE != hMem) GlobalLock(hMem);
513 }
514 
515 /*
516  * @implemented
517  */
518 UINT
519 NTAPI
GlobalFlags(HGLOBAL hMem)520 GlobalFlags(HGLOBAL hMem)
521 {
522     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
523     HANDLE Handle = NULL;
524     ULONG Flags = 0;
525     UINT uFlags = GMEM_INVALID_HANDLE;
526 
527     /* Start by locking the heap */
528     RtlLockHeap(BaseHeap);
529     _SEH2_TRY
530     {
531         /* Check if this is a simple RTL Heap Managed block */
532         if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
533         {
534             /* Then we'll query RTL Heap */
535             RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags);
536             BASE_TRACE_PTR(Handle, hMem);
537 
538             /*
539              * Check if RTL Heap didn't find a handle associated with us or
540              * said that this heap isn't movable, which means something we're
541              * really not a handle-based heap.
542              */
543             if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
544             {
545                 /* Then set the flags to 0 */
546                 uFlags = 0;
547             }
548             else
549             {
550                 /* Otherwise we're handle-based, so get the internal handle */
551                 hMem = Handle;
552             }
553         }
554 
555         /* Check if the handle is actually an entry in our table */
556         if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
557         {
558             /* Then get the entry */
559             HandleEntry = BaseHeapGetEntry(hMem);
560             BASE_TRACE_HANDLE(HandleEntry, hMem);
561 
562             /* Make sure it's a valid handle */
563             if (BaseHeapValidateEntry(HandleEntry))
564             {
565                 /* Get the lock count first */
566                 uFlags = HandleEntry->LockCount & GMEM_LOCKCOUNT;
567 
568                 /* Now check if it's discardable */
569                 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE)
570                 {
571                     /* Set the Win32 Flag */
572                     uFlags |= GMEM_DISCARDABLE;
573                 }
574 
575                 /* Check if it's DDE Shared */
576                 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_DDESHARE)
577                 {
578                     /* Set the Win32 Flag */
579                     uFlags |= GMEM_DDESHARE;
580                 }
581 
582                 /* Now check if it's discarded */
583                 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
584                 {
585                    /* Set the Win32 Flag */
586                    uFlags |= GMEM_DISCARDED;
587                }
588             }
589         }
590 
591         /* Check if by now, we still haven't gotten any useful flags */
592         if (uFlags == GMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE);
593     }
594     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
595     {
596         /* Set the exception code */
597         BaseSetLastNTError(_SEH2_GetExceptionCode());
598     }
599     _SEH2_END;
600 
601     /* All done! Unlock heap and return Win32 Flags */
602     RtlUnlockHeap(BaseHeap);
603     return uFlags;
604 }
605 
606 /*
607  * @implemented
608  */
609 HGLOBAL
610 NTAPI
GlobalFree(HGLOBAL hMem)611 GlobalFree(HGLOBAL hMem)
612 {
613     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
614     LPVOID Ptr;
615     BASE_TRACE_DEALLOC(hMem);
616 
617     /* Check if this was a simple allocated heap entry */
618     if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
619     {
620         /* Free it with the RTL Heap Manager */
621         if (RtlFreeHeap(BaseHeap, 0, hMem))
622         {
623             /* Return NULL since there's no handle */
624             return NULL;
625         }
626         else
627         {
628             /* Otherwise fail */
629             BASE_TRACE_FAILURE();
630             SetLastError(ERROR_INVALID_HANDLE);
631             return hMem;
632         }
633     }
634 
635     /* It's a handle probably, so lock the heap */
636     RtlLockHeap(BaseHeap);
637     _SEH2_TRY
638     {
639         /* Make sure that this is an entry in our handle database */
640         if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
641         {
642             /* Get the entry */
643             HandleEntry = BaseHeapGetEntry(hMem);
644             BASE_TRACE_HANDLE(HandleEntry, hMem);
645 
646             /* Make sure the handle is valid */
647             if (!BaseHeapValidateEntry(HandleEntry))
648             {
649                 /* It's not, fail */
650                 SetLastError(ERROR_INVALID_HANDLE);
651                 Ptr = NULL;
652             }
653             else
654             {
655                 /* It's valid, so get the pointer */
656                 Ptr = HandleEntry->Object;
657 
658                 /* Free this handle */
659                 BaseHeapFreeEntry(HandleEntry);
660 
661                 /* If the pointer is 0, then we don't have a handle either */
662                 if (!Ptr) hMem = NULL;
663             }
664         }
665         else
666         {
667             /* Otherwise, reuse the handle as a pointer */
668             BASE_TRACE_FAILURE();
669             Ptr = hMem;
670         }
671 
672         /* Check if we got here with a valid heap pointer */
673         if (Ptr)
674         {
675             /* Free it with the RTL Heap Manager */
676             if (RtlFreeHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr))
677             {
678                 /* Everything worked */
679                 hMem = NULL;
680             }
681             else
682             {
683                 /* This wasn't a real heap handle */
684                 SetLastError(ERROR_INVALID_HANDLE);
685             }
686         }
687     }
688     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
689     {
690         /* Set the exception code */
691         BaseSetLastNTError(_SEH2_GetExceptionCode());
692     }
693     _SEH2_END;
694 
695     /* We're done, so unlock the heap and return the handle */
696     RtlUnlockHeap(BaseHeap);
697     return hMem;
698 }
699 
700 /*
701  * @implemented
702  */
703 HGLOBAL
704 NTAPI
GlobalHandle(LPCVOID pMem)705 GlobalHandle(LPCVOID pMem)
706 {
707     HANDLE Handle = NULL;
708     ULONG Flags;
709 
710     /* Lock the heap */
711     RtlLockHeap(BaseHeap);
712     _SEH2_TRY
713     {
714         /* Query RTL Heap */
715         if (!RtlGetUserInfoHeap(BaseHeap,
716                                 HEAP_NO_SERIALIZE,
717                                 (PVOID)pMem,
718                                 &Handle,
719                                 &Flags))
720         {
721             /* RTL Heap Manager does not know about this heap */
722             SetLastError(ERROR_INVALID_HANDLE);
723         }
724         else
725         {
726             /*
727              * Check if RTL Heap didn't find a handle for us or said that
728              * this heap isn't movable.
729              */
730             BASE_TRACE_PTR(Handle, pMem);
731             if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
732             {
733                 /* We're actually handle-based, so the pointer is a handle */
734                 Handle = (HANDLE)pMem;
735             }
736         }
737     }
738     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
739     {
740         /* Set the exception code */
741         BaseSetLastNTError(_SEH2_GetExceptionCode());
742     }
743     _SEH2_END;
744 
745     /* All done, unlock the heap and return the handle */
746     RtlUnlockHeap(BaseHeap);
747     return Handle;
748 }
749 
750 /*
751  * @implemented
752  */
753 LPVOID
754 NTAPI
GlobalLock(HGLOBAL hMem)755 GlobalLock(HGLOBAL hMem)
756 {
757     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
758     LPVOID Ptr;
759 
760     /* Check if this was a simple allocated heap entry */
761     if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
762     {
763         /* Make sure it's not a kernel or invalid address */
764         if ((hMem >= (HGLOBAL)SystemRangeStart) || (IsBadReadPtr(hMem, 1)))
765         {
766             /* Signal an error */
767             SetLastError(ERROR_INVALID_HANDLE);
768             return NULL;
769         }
770 
771         /* It's all good */
772         return hMem;
773     }
774 
775     /* Otherwise, lock the heap */
776     RtlLockHeap(BaseHeap);
777     _SEH2_TRY
778     {
779         /* Get the handle entry */
780         HandleEntry = BaseHeapGetEntry(hMem);
781         BASE_TRACE_HANDLE(HandleEntry, hMem);
782 
783         /* Make sure it's valid */
784         if (!BaseHeapValidateEntry(HandleEntry))
785         {
786             /* It's not, fail */
787             BASE_TRACE_FAILURE();
788             SetLastError(ERROR_INVALID_HANDLE);
789             Ptr = NULL;
790         }
791         else
792         {
793             /* Otherwise, get the pointer */
794             Ptr = HandleEntry->Object;
795             if (Ptr)
796             {
797                 /* Increase the lock count, unless we've went too far */
798                 if (HandleEntry->LockCount++ == GMEM_LOCKCOUNT)
799                 {
800                     /* In which case we simply unlock once */
801                     HandleEntry->LockCount--;
802                 }
803             }
804             else
805             {
806                 /* The handle is still there but the memory was already freed */
807                 SetLastError(ERROR_DISCARDED);
808             }
809         }
810     }
811     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
812     {
813         SetLastError(ERROR_INVALID_HANDLE);
814         Ptr = NULL;
815     }
816     _SEH2_END;
817 
818     /* All done. Unlock the heap and return the pointer */
819     RtlUnlockHeap(BaseHeap);
820     return Ptr;
821 }
822 
823 HGLOBAL
824 NTAPI
GlobalReAlloc(HGLOBAL hMem,SIZE_T dwBytes,UINT uFlags)825 GlobalReAlloc(HGLOBAL hMem,
826               SIZE_T dwBytes,
827               UINT uFlags)
828 {
829     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
830     HANDLE Handle;
831     LPVOID Ptr;
832     ULONG Flags = 0;
833 
834     /* Throw out invalid flags */
835     if (uFlags & ~(GMEM_VALID_FLAGS | GMEM_MODIFY))
836     {
837         SetLastError(ERROR_INVALID_PARAMETER);
838         return NULL;
839     }
840 
841     /* Throw out invalid combo */
842     if ((uFlags & GMEM_DISCARDABLE) && !(uFlags & GMEM_MODIFY))
843     {
844         SetLastError(ERROR_INVALID_PARAMETER);
845         return NULL;
846     }
847 
848     /* Convert ZEROINIT */
849     if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
850 
851     /* If this wasn't a movable heap, then we MUST re-alloc in place */
852     if (!(uFlags & GMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
853 
854     /* Lock the heap and disable built-in locking in the RTL Heap functions */
855     RtlLockHeap(BaseHeap);
856     Flags |= HEAP_NO_SERIALIZE;
857 
858     /* Check if this is a simple handle-based block */
859     if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
860     {
861         /* Get the entry */
862         HandleEntry = BaseHeapGetEntry(hMem);
863         BASE_TRACE_HANDLE(HandleEntry, hMem);
864 
865         /* Make sure the handle is valid */
866         if (!BaseHeapValidateEntry(HandleEntry))
867         {
868             /* Fail */
869             BASE_TRACE_FAILURE();
870             SetLastError(ERROR_INVALID_HANDLE);
871             hMem = NULL;
872         }
873         else if (uFlags & GMEM_MODIFY)
874         {
875             /* User is changing flags... check if the memory was discardable */
876             if (uFlags & GMEM_DISCARDABLE)
877             {
878                 /* Then set the flag */
879                 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
880             }
881             else
882             {
883                 /* Otherwise, remove the flag */
884                 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSABLE;
885             }
886         }
887         else
888         {
889             /* Otherwise, get the object and check if we have no size */
890             Ptr = HandleEntry->Object;
891             if (!dwBytes)
892             {
893                 /* Clear the handle and check for a pointer */
894                 hMem = NULL;
895                 if (Ptr)
896                 {
897                     /* Make sure the handle isn't locked */
898                     if ((uFlags & GMEM_MOVEABLE) && !(HandleEntry->LockCount))
899                     {
900                         /* Free the current heap */
901                         if (RtlFreeHeap(BaseHeap, Flags, Ptr))
902                         {
903                             /* Free the handle */
904                             HandleEntry->Object = NULL;
905                             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
906 
907                             /* Get the object pointer */
908                             hMem = &HandleEntry->Object;
909                         }
910                     }
911                 }
912                 else
913                 {
914                     /* Otherwise just return the object pointer */
915                     hMem = &HandleEntry->Object;
916                 }
917             }
918             else
919             {
920                 /* Otherwise, we're allocating, so set the new flags needed */
921                 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
922                 if (!Ptr)
923                 {
924                     /* We don't have a base, so allocate one */
925                     Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
926                     BASE_TRACE_ALLOC2(Ptr);
927                     if (Ptr)
928                     {
929                         /* Allocation succeeded, so save our entry */
930                         RtlSetUserValueHeap(BaseHeap,
931                                             HEAP_NO_SERIALIZE,
932                                             Ptr,
933                                             hMem);
934                     }
935                 }
936                 else
937                 {
938                     /*
939                      * If it's not movable or currently locked, we MUST allocate
940                      * in-place!
941                      */
942                     if (!(uFlags & GMEM_MOVEABLE) && (HandleEntry->LockCount))
943                     {
944                         /* Set the flag */
945                         Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
946                     }
947                     else
948                     {
949                         /* Otherwise clear the flag if we set it previously */
950                         Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
951                     }
952 
953                     /* Do the re-allocation. No need to save the entry again */
954                     Ptr = RtlReAllocateHeap(BaseHeap, Flags, Ptr, dwBytes);
955                 }
956 
957                 /* Make sure we have a pointer by now */
958                 if (Ptr)
959                 {
960                     /* Write it in the handle entry and mark it in use */
961                     HandleEntry->Object = Ptr;
962                     HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE;
963                 }
964                 else
965                 {
966                     /* Otherwise we failed */
967                     hMem = NULL;
968                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
969                 }
970             }
971         }
972     }
973     else if (uFlags & GMEM_MODIFY)
974     {
975         /* This is not a handle-based heap and the caller wants it to be one */
976         if (uFlags & GMEM_MOVEABLE)
977         {
978             /* Get information on its current state */
979             Handle = hMem;
980             if (RtlGetUserInfoHeap(BaseHeap,
981                                    HEAP_NO_SERIALIZE,
982                                    hMem,
983                                    &Handle,
984                                    NULL))
985             {
986                 /*
987                  * Check if the handle matches the pointer or the moveable flag
988                  * isn't there, which is what we expect since it currently isn't.
989                  */
990                 if ((Handle == hMem) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
991                 {
992                     /* Allocate a handle for it */
993                     HandleEntry = BaseHeapAllocEntry();
994                     if (!HandleEntry)
995                     {
996                         /* No entry could be allocated */
997                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
998                         RtlUnlockHeap(BaseHeap);
999                         return NULL;
1000                     }
1001 
1002                     /* Calculate the size of the current heap */
1003                     dwBytes = RtlSizeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem);
1004 
1005                     /* Set the movable flag */
1006                     Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
1007 
1008                     /* Now allocate the actual heap for it */
1009                     HandleEntry->Object = RtlAllocateHeap(BaseHeap,
1010                                                           Flags,
1011                                                           dwBytes);
1012                     BASE_TRACE_PTR(HandleEntry->Object, HandleEntry);
1013                     if (!HandleEntry->Object)
1014                     {
1015                         /*
1016                          * We failed, manually set the allocate flag and
1017                          * free the handle
1018                          */
1019                         HandleEntry->Flags = RTL_HANDLE_VALID;
1020                         BaseHeapFreeEntry(HandleEntry);
1021 
1022                         /* For the cleanup case */
1023                         BASE_TRACE_FAILURE();
1024                         HandleEntry = NULL;
1025                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1026                     }
1027                     else
1028                     {
1029                         /* Otherwise, copy the new heap and free the old one */
1030                         RtlMoveMemory(HandleEntry->Object, hMem, dwBytes);
1031                         RtlFreeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem);
1032 
1033                         /* Select the heap pointer */
1034                         hMem = (HANDLE)&HandleEntry->Object;
1035 
1036                         /* Initialize the count and default flags */
1037                         HandleEntry->LockCount = 0;
1038                         HandleEntry->Flags = RTL_HANDLE_VALID |
1039                                              BASE_HEAP_ENTRY_FLAG_MOVABLE;
1040 
1041                         /* Check if it's also discardable */
1042                         if (uFlags & GMEM_DISCARDABLE)
1043                         {
1044                             /* Set the internal flag */
1045                             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
1046                         }
1047 
1048                         /* Check if it's also DDE Shared */
1049                         if (uFlags & GMEM_DDESHARE)
1050                         {
1051                             /* Set the internal flag */
1052                             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
1053                         }
1054 
1055                         /* Allocation succeeded, so save our entry */
1056                         RtlSetUserValueHeap(BaseHeap,
1057                                             HEAP_NO_SERIALIZE,
1058                                             HandleEntry->Object,
1059                                             hMem);
1060                     }
1061                 }
1062             }
1063         }
1064     }
1065     else
1066     {
1067         /* Otherwise, this is a simple RTL Managed Heap, so just call it */
1068         hMem = RtlReAllocateHeap(BaseHeap,
1069                                  Flags | HEAP_NO_SERIALIZE,
1070                                  hMem,
1071                                  dwBytes);
1072         if (!hMem)
1073         {
1074             /* Fail */
1075             BASE_TRACE_FAILURE();
1076             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1077         }
1078     }
1079 
1080     /* All done, unlock the heap and return the pointer */
1081     RtlUnlockHeap(BaseHeap);
1082     return hMem;
1083 }
1084 
1085 /*
1086  * @implemented
1087  */
1088 SIZE_T
1089 NTAPI
GlobalSize(HGLOBAL hMem)1090 GlobalSize(HGLOBAL hMem)
1091 {
1092     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1093     PVOID Handle = NULL;
1094     ULONG Flags = 0;
1095     SIZE_T dwSize = MAXULONG_PTR;
1096 
1097     /* Lock the heap */
1098     RtlLockHeap(BaseHeap);
1099     _SEH2_TRY
1100     {
1101         /* Check if this is a simple RTL Heap Managed block */
1102         if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
1103         {
1104             /* Then we'll query RTL Heap */
1105             if (RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags))
1106             {
1107                 BASE_TRACE_PTR(Handle, hMem);
1108                 /*
1109                  * Check if RTL Heap didn't give us a handle or said that this
1110                  * heap isn't movable.
1111                  */
1112                 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
1113                 {
1114                     /* We're not a handle heap, so use the generic call */
1115                     dwSize = RtlSizeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem);
1116                 }
1117                 else
1118                 {
1119                     /* We're a handle heap so get the internal handle */
1120                     hMem = Handle;
1121                 }
1122             }
1123         }
1124 
1125         /* Make sure that this is an entry in our handle database */
1126         if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
1127         {
1128             /* Get the entry */
1129             HandleEntry = BaseHeapGetEntry(hMem);
1130             BASE_TRACE_HANDLE(HandleEntry, hMem);
1131 
1132             /* Make sure the handle is valid */
1133             if (!BaseHeapValidateEntry(HandleEntry))
1134             {
1135                 /* Fail */
1136                 BASE_TRACE_FAILURE();
1137                 SetLastError(ERROR_INVALID_HANDLE);
1138             }
1139             else if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
1140             {
1141                 /* We've reused this block, but we've saved the size for you */
1142                 dwSize = HandleEntry->OldSize;
1143             }
1144             else
1145             {
1146                 /* Otherwise, query RTL about it */
1147                 dwSize = RtlSizeHeap(BaseHeap,
1148                                      HEAP_NO_SERIALIZE,
1149                                      HandleEntry->Object);
1150             }
1151         }
1152     }
1153     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1154     {
1155         /* Set failure for later */
1156         dwSize = MAXULONG_PTR;
1157     }
1158     _SEH2_END;
1159 
1160     /* Check if by now, we still haven't gotten any useful size */
1161     if (dwSize == MAXULONG_PTR)
1162     {
1163         /* Fail */
1164         BASE_TRACE_FAILURE();
1165         SetLastError(ERROR_INVALID_HANDLE);
1166         dwSize = 0;
1167     }
1168 
1169     /* All done! Unlock heap and return the size */
1170     RtlUnlockHeap(BaseHeap);
1171     return dwSize;
1172 }
1173 
1174 /*
1175  * @implemented
1176  */
1177 VOID
1178 NTAPI
GlobalUnfix(HGLOBAL hMem)1179 GlobalUnfix(HGLOBAL hMem)
1180 {
1181     /* If the handle is valid, unlock it */
1182     if (hMem != INVALID_HANDLE_VALUE) GlobalUnlock(hMem);
1183 }
1184 
1185 /*
1186  * @implemented
1187  */
1188 BOOL
1189 NTAPI
GlobalUnlock(HGLOBAL hMem)1190 GlobalUnlock(HGLOBAL hMem)
1191 {
1192     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1193     BOOL RetVal = TRUE;
1194 
1195     /* Check if this was a simple allocated heap entry */
1196     if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) return RetVal;
1197 
1198     /* Otherwise, lock the heap */
1199     RtlLockHeap(BaseHeap);
1200 
1201     /* Get the handle entry */
1202     HandleEntry = BaseHeapGetEntry(hMem);
1203     BASE_TRACE_HANDLE(HandleEntry, hMem);
1204 
1205     _SEH2_TRY
1206     {
1207         /* Make sure it's valid */
1208         if (!BaseHeapValidateEntry(HandleEntry))
1209         {
1210             /* It's not, fail */
1211             BASE_TRACE_FAILURE();
1212             SetLastError(ERROR_INVALID_HANDLE);
1213             RetVal = FALSE;
1214         }
1215         else
1216         {
1217             /* Otherwise, decrement lock count, unless we're already at 0*/
1218             if (!HandleEntry->LockCount--)
1219             {
1220                 /* In which case we simply lock it back and fail */
1221                 HandleEntry->LockCount++;
1222                 SetLastError(ERROR_NOT_LOCKED);
1223                 RetVal = FALSE;
1224             }
1225             else if (!HandleEntry->LockCount)
1226             {
1227                 /* Nothing to unlock */
1228                 SetLastError(NO_ERROR);
1229                 RetVal = FALSE;
1230             }
1231         }
1232     }
1233     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1234     {
1235         SetLastError(ERROR_INVALID_PARAMETER);
1236         RetVal = FALSE;
1237     }
1238     _SEH2_END;
1239 
1240     /* All done. Unlock the heap and return the pointer */
1241     RtlUnlockHeap(BaseHeap);
1242     return RetVal;
1243 }
1244 
1245 /*
1246  * @implemented
1247  */
1248 BOOL
1249 NTAPI
GlobalUnWire(HGLOBAL hMem)1250 GlobalUnWire(HGLOBAL hMem)
1251 {
1252     /* This is simply an unlock */
1253     return GlobalUnlock(hMem);
1254 }
1255 
1256 /*
1257  * @implemented
1258  */
1259 LPVOID
1260 NTAPI
GlobalWire(HGLOBAL hMem)1261 GlobalWire(HGLOBAL hMem)
1262 {
1263     /* This is just a lock */
1264     return GlobalLock(hMem);
1265 }
1266 
1267 /*
1268  * @implemented
1269  */
1270 BOOL
1271 NTAPI
GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer)1272 GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer)
1273 {
1274     SYSTEM_PERFORMANCE_INFORMATION PerformanceInfo;
1275     VM_COUNTERS VmCounters;
1276     QUOTA_LIMITS QuotaLimits;
1277     ULONGLONG PageFile, PhysicalMemory;
1278     NTSTATUS Status;
1279 
1280     if (lpBuffer->dwLength != sizeof(*lpBuffer))
1281     {
1282         SetLastError(ERROR_INVALID_PARAMETER);
1283         return FALSE;
1284     }
1285 
1286     /* Query performance information */
1287     Status = NtQuerySystemInformation(SystemPerformanceInformation,
1288                                       &PerformanceInfo,
1289                                       sizeof(PerformanceInfo),
1290                                       NULL);
1291     if (!NT_SUCCESS(Status))
1292     {
1293         BaseSetLastNTError(Status);
1294         return FALSE;
1295     }
1296 
1297     /* Calculate memory load */
1298     lpBuffer->dwMemoryLoad = ((DWORD)(BaseStaticServerData->SysInfo.NumberOfPhysicalPages -
1299                                       PerformanceInfo.AvailablePages) * 100) /
1300                                       BaseStaticServerData->SysInfo.NumberOfPhysicalPages;
1301 
1302     /* Save physical memory */
1303     PhysicalMemory = BaseStaticServerData->SysInfo.NumberOfPhysicalPages *
1304                      BaseStaticServerData->SysInfo.PageSize;
1305     lpBuffer->ullTotalPhys = PhysicalMemory;
1306 
1307     /* Now save available physical memory */
1308     PhysicalMemory = PerformanceInfo.AvailablePages *
1309                      BaseStaticServerData->SysInfo.PageSize;
1310     lpBuffer->ullAvailPhys = PhysicalMemory;
1311 
1312     /* Query VM and Quota Limits */
1313     Status = NtQueryInformationProcess(NtCurrentProcess(),
1314                                        ProcessQuotaLimits,
1315                                        &QuotaLimits,
1316                                        sizeof(QUOTA_LIMITS),
1317                                        NULL);
1318     if (!NT_SUCCESS(Status))
1319     {
1320         BaseSetLastNTError(Status);
1321         return FALSE;
1322     }
1323 
1324     Status = NtQueryInformationProcess(NtCurrentProcess(),
1325                                        ProcessVmCounters,
1326                                        &VmCounters,
1327                                        sizeof(VM_COUNTERS),
1328                                        NULL);
1329     if (!NT_SUCCESS(Status))
1330     {
1331         BaseSetLastNTError(Status);
1332         return FALSE;
1333     }
1334 
1335     /* Save the commit limit */
1336     lpBuffer->ullTotalPageFile = min(QuotaLimits.PagefileLimit,
1337                                      PerformanceInfo.CommitLimit);
1338     lpBuffer->ullTotalPageFile *= BaseStaticServerData->SysInfo.PageSize;
1339 
1340     /* Calculate how many pages are left */
1341     PageFile = PerformanceInfo.CommitLimit - PerformanceInfo.CommittedPages;
1342 
1343     /* Save the total */
1344     lpBuffer->ullAvailPageFile = min(PageFile,
1345                                      QuotaLimits.PagefileLimit -
1346                                      VmCounters.PagefileUsage);
1347     lpBuffer->ullAvailPageFile *= BaseStaticServerData->SysInfo.PageSize;
1348 
1349     /* Now calculate the total virtual space */
1350     lpBuffer->ullTotalVirtual = (BaseStaticServerData->SysInfo.MaximumUserModeAddress -
1351                                  BaseStaticServerData->SysInfo.MinimumUserModeAddress) + 1;
1352 
1353     /* And finally the available virtual space */
1354     lpBuffer->ullAvailVirtual = lpBuffer->ullTotalVirtual - VmCounters.VirtualSize;
1355     lpBuffer->ullAvailExtendedVirtual = 0;
1356 
1357     return TRUE;
1358 }
1359 
1360 /*
1361  * @implemented
1362  */
1363 VOID
1364 NTAPI
GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)1365 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
1366 {
1367     MEMORYSTATUSEX lpBufferEx;
1368 
1369     /* Call the extended function */
1370     lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX);
1371     if (GlobalMemoryStatusEx(&lpBufferEx))
1372     {
1373         /* Reset the right size and fill out the information */
1374         lpBuffer->dwLength = sizeof(MEMORYSTATUS);
1375         lpBuffer->dwMemoryLoad = lpBufferEx.dwMemoryLoad;
1376         lpBuffer->dwTotalPhys = (SIZE_T)min(lpBufferEx.ullTotalPhys, MAXULONG_PTR);
1377         lpBuffer->dwAvailPhys = (SIZE_T)min(lpBufferEx.ullAvailPhys, MAXULONG_PTR);
1378         lpBuffer->dwTotalPageFile = (SIZE_T)min(lpBufferEx.ullTotalPageFile, MAXULONG_PTR);
1379         lpBuffer->dwAvailPageFile = (SIZE_T)min(lpBufferEx.ullAvailPageFile, MAXULONG_PTR);
1380         lpBuffer->dwTotalVirtual = (SIZE_T)min(lpBufferEx.ullTotalVirtual, MAXULONG_PTR);
1381         lpBuffer->dwAvailVirtual = (SIZE_T)min(lpBufferEx.ullAvailVirtual, MAXULONG_PTR);
1382     }
1383 }
1384 
1385 /*
1386  * @implemented
1387  */
1388 HLOCAL
1389 NTAPI
LocalAlloc(UINT uFlags,SIZE_T dwBytes)1390 LocalAlloc(UINT uFlags,
1391            SIZE_T dwBytes)
1392 {
1393     ULONG Flags = 0;
1394     PVOID Ptr = NULL;
1395     HANDLE hMemory;
1396     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1397     BASE_TRACE_ALLOC(dwBytes, uFlags);
1398     ASSERT(BaseHeap);
1399 
1400     /* Make sure the flags are valid */
1401     if (uFlags & ~LMEM_VALID_FLAGS)
1402     {
1403         /* They aren't, fail */
1404         BASE_TRACE_FAILURE();
1405         SetLastError(ERROR_INVALID_PARAMETER);
1406         return NULL;
1407     }
1408 
1409     /* Convert ZEROINIT */
1410     if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
1411 
1412     /* Check if we're not movable, which means pointer-based heap */
1413     if (!(uFlags & LMEM_MOVEABLE))
1414     {
1415         /* Allocate heap for it */
1416         Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
1417         BASE_TRACE_ALLOC2(Ptr);
1418         return Ptr;
1419     }
1420 
1421     /* This is heap based, so lock it in first */
1422     RtlLockHeap(BaseHeap);
1423 
1424     /*
1425      * Disable locking, enable custom flags, and write the
1426      * movable flag (deprecated)
1427      */
1428     Flags |= HEAP_NO_SERIALIZE |
1429              HEAP_SETTABLE_USER_VALUE |
1430              BASE_HEAP_FLAG_MOVABLE;
1431 
1432     /* Allocate the handle */
1433     HandleEntry = BaseHeapAllocEntry();
1434     if (!HandleEntry)
1435     {
1436         /* Fail */
1437         hMemory = NULL;
1438         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1439         BASE_TRACE_FAILURE();
1440         goto Quickie;
1441     }
1442 
1443     /* Get the object and make sure we have size */
1444     hMemory = &HandleEntry->Object;
1445     if (dwBytes)
1446     {
1447         /* Allocate the actual memory for it */
1448         Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
1449         BASE_TRACE_PTR(HandleEntry, Ptr);
1450         if (!Ptr)
1451         {
1452             /* We failed, manually set the allocate flag and free the handle */
1453             HandleEntry->Flags = RTL_HANDLE_VALID;
1454             BaseHeapFreeEntry(HandleEntry);
1455 
1456             /* For the cleanup case */
1457             HandleEntry = NULL;
1458         }
1459         else
1460         {
1461             /* All worked well, save our heap entry */
1462             RtlSetUserValueHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr, hMemory);
1463         }
1464     }
1465 
1466 Quickie:
1467     /* Cleanup! First unlock the heap */
1468     RtlUnlockHeap(BaseHeap);
1469 
1470     /* Check if a handle was allocated */
1471     if (HandleEntry)
1472     {
1473         /* Set the pointer and allocated flag */
1474         HandleEntry->Object = Ptr;
1475         HandleEntry->Flags = RTL_HANDLE_VALID;
1476         if (!Ptr)
1477         {
1478             /* We don't have a valid pointer, but so reuse this handle */
1479             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
1480         }
1481 
1482         /* Check if the handle is discardable */
1483         if (uFlags & GMEM_DISCARDABLE)
1484         {
1485             /* Save it in the handle entry */
1486             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
1487         }
1488 
1489         /* Check if the handle is moveable */
1490         if (uFlags & GMEM_MOVEABLE)
1491         {
1492             /* Save it in the handle entry */
1493             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE;
1494         }
1495 
1496         /* Set the pointer */
1497         Ptr = hMemory;
1498     }
1499 
1500     /* Return the pointer */
1501     return Ptr;
1502 }
1503 
1504 /*
1505  * @implemented
1506  */
1507 SIZE_T
1508 NTAPI
LocalCompact(UINT dwMinFree)1509 LocalCompact(UINT dwMinFree)
1510 {
1511     /* Call the RTL Heap Manager */
1512     return RtlCompactHeap(BaseHeap, 0);
1513 }
1514 
1515 /*
1516  * @implemented
1517  */
1518 UINT
1519 NTAPI
LocalFlags(HLOCAL hMem)1520 LocalFlags(HLOCAL hMem)
1521 {
1522     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1523     HANDLE Handle = NULL;
1524     ULONG Flags = 0;
1525     UINT uFlags = LMEM_INVALID_HANDLE;
1526 
1527     /* Start by locking the heap */
1528     RtlLockHeap(BaseHeap);
1529 
1530     /* Check if this is a simple RTL Heap Managed block */
1531     if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
1532     {
1533         /* Then we'll query RTL Heap */
1534         RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags);
1535         BASE_TRACE_PTR(Handle, hMem);
1536 
1537         /*
1538          * Check if RTL Heap didn't find a handle associated with us or
1539          * said that this heap isn't movable, which means something we're
1540          * really not a handle-based heap.
1541          */
1542         if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
1543         {
1544             /* Then set the flags to 0 */
1545             uFlags = 0;
1546         }
1547         else
1548         {
1549             /* Otherwise we're handle-based, so get the internal handle */
1550             hMem = Handle;
1551         }
1552     }
1553 
1554     /* Check if the handle is actually an entry in our table */
1555     if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
1556     {
1557         /* Then get the entry */
1558         HandleEntry = BaseHeapGetEntry(hMem);
1559         BASE_TRACE_HANDLE(HandleEntry, hMem);
1560 
1561         /* Make sure it's a valid handle */
1562         if (BaseHeapValidateEntry(HandleEntry))
1563         {
1564             /* Get the lock count first */
1565             uFlags = HandleEntry->LockCount & LMEM_LOCKCOUNT;
1566 
1567             /* Now check if it's discardable */
1568             if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE)
1569             {
1570                 /* Set the Win32 Flag */
1571                 uFlags |= LMEM_DISCARDABLE;
1572             }
1573 
1574             /* Now check if it's discarded */
1575             if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
1576                /* Set the Win32 Flag */
1577                uFlags |= LMEM_DISCARDED;
1578         }
1579     }
1580 
1581     /* Check if by now, we still haven't gotten any useful flags */
1582     if (uFlags == LMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE);
1583 
1584     /* All done! Unlock heap and return Win32 Flags */
1585     RtlUnlockHeap(BaseHeap);
1586     return uFlags;
1587 }
1588 
1589 /*
1590  * @implemented
1591  */
1592 HLOCAL
1593 NTAPI
LocalFree(HLOCAL hMem)1594 LocalFree(HLOCAL hMem)
1595 {
1596     /* This is identical to a Global Free */
1597     return GlobalFree(hMem);
1598 }
1599 
1600 /*
1601  * @implemented
1602  */
1603 HLOCAL
1604 NTAPI
LocalHandle(LPCVOID pMem)1605 LocalHandle(LPCVOID pMem)
1606 {
1607     /* This is identical to a Global Handle */
1608     return GlobalHandle(pMem);
1609 }
1610 
1611 /*
1612  * @implemented
1613  */
1614 LPVOID
1615 NTAPI
LocalLock(HLOCAL hMem)1616 LocalLock(HLOCAL hMem)
1617 {
1618     /* This is the same as a GlobalLock, assuming these never change */
1619     C_ASSERT(LMEM_LOCKCOUNT == GMEM_LOCKCOUNT);
1620     return GlobalLock(hMem);
1621 }
1622 
1623 HLOCAL
1624 NTAPI
LocalReAlloc(HLOCAL hMem,SIZE_T dwBytes,UINT uFlags)1625 LocalReAlloc(HLOCAL hMem,
1626              SIZE_T dwBytes,
1627              UINT uFlags)
1628 {
1629     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1630     LPVOID Ptr;
1631     ULONG Flags = 0;
1632 
1633     /* Convert ZEROINIT */
1634     if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
1635 
1636     /* If this wasn't a movable heap, then we MUST re-alloc in place */
1637     if (!(uFlags & LMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
1638 
1639     /* Lock the heap and disable built-in locking in the RTL Heap functions */
1640     RtlLockHeap(BaseHeap);
1641     Flags |= HEAP_NO_SERIALIZE;
1642 
1643     /* Check if this is a simple handle-based block */
1644     if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
1645     {
1646         /* Get the entry */
1647         HandleEntry = BaseHeapGetEntry(hMem);
1648         BASE_TRACE_HANDLE(HandleEntry, hMem);
1649 
1650         /* Make sure the handle is valid */
1651         if (!BaseHeapValidateEntry(HandleEntry))
1652         {
1653             /* Fail */
1654             BASE_TRACE_FAILURE();
1655             SetLastError(ERROR_INVALID_HANDLE);
1656             hMem = NULL;
1657         }
1658         else if (uFlags & LMEM_MODIFY)
1659         {
1660             /* User is changing flags... check if the memory was discardable */
1661             if (uFlags & LMEM_DISCARDABLE)
1662             {
1663                 /* Then set the flag */
1664                 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
1665             }
1666             else
1667             {
1668                 /* Otherwise, remove the flag */
1669                 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSABLE;
1670             }
1671         }
1672         else
1673         {
1674             /* Otherwise, get the object and check if we have no size */
1675             Ptr = HandleEntry->Object;
1676             if (!dwBytes)
1677             {
1678                 /* Clear the handle and check for a pointer */
1679                 hMem = NULL;
1680                 if (Ptr)
1681                 {
1682                     /* Make sure the handle isn't locked */
1683                     if ((uFlags & LMEM_MOVEABLE) && !(HandleEntry->LockCount))
1684                     {
1685                         /* Free the current heap */
1686                         RtlFreeHeap(BaseHeap, Flags, Ptr);
1687 
1688                         /* Free the handle */
1689                         HandleEntry->Object = NULL;
1690                         HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
1691 
1692                         /* Get the object pointer */
1693                         hMem = &HandleEntry->Object;
1694                     }
1695                 }
1696                 else
1697                 {
1698                     /* Otherwise just return the object pointer */
1699                     hMem = &HandleEntry->Object;
1700                 }
1701             }
1702             else
1703             {
1704                 /* Otherwise, we're allocating, so set the new flags needed */
1705                 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
1706                 if (!Ptr)
1707                 {
1708                     /* We don't have a base, so allocate one */
1709                     Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
1710                     BASE_TRACE_ALLOC2(Ptr);
1711                     if (Ptr)
1712                     {
1713                         /* Allocation succeeded, so save our entry */
1714                         RtlSetUserValueHeap(BaseHeap,
1715                                             HEAP_NO_SERIALIZE,
1716                                             Ptr,
1717                                             hMem);
1718                     }
1719                 }
1720                 else
1721                 {
1722                     /*
1723                      * If it's not movable or currently locked, we MUST allocate
1724                      * in-place!
1725                      */
1726                     if (!(uFlags & LMEM_MOVEABLE) && (HandleEntry->LockCount))
1727                     {
1728                         /* Set the flag */
1729                         Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
1730                     }
1731                     else
1732                     {
1733                         /* Otherwise clear the flag if we set it previously */
1734                         Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
1735                     }
1736 
1737                     /* And do the re-allocation */
1738                     Ptr = RtlReAllocateHeap(BaseHeap, Flags, Ptr, dwBytes);
1739                 }
1740 
1741                 /* Make sure we have a pointer by now */
1742                 if (Ptr)
1743                 {
1744                     /* Write it in the handle entry and mark it in use */
1745                     HandleEntry->Object = Ptr;
1746                     HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE;
1747                 }
1748                 else
1749                 {
1750                     /* Otherwise we failed */
1751                     hMem = NULL;
1752                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1753                 }
1754             }
1755         }
1756     }
1757     else if (!(uFlags & LMEM_MODIFY))
1758     {
1759         /* Otherwise, this is a simple RTL Managed Heap, so just call it */
1760         hMem = RtlReAllocateHeap(BaseHeap,
1761                                  Flags | HEAP_NO_SERIALIZE,
1762                                  hMem,
1763                                  dwBytes);
1764         if (!hMem)
1765         {
1766             /* Fail */
1767             BASE_TRACE_FAILURE();
1768             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1769         }
1770     }
1771 
1772     /* All done, unlock the heap and return the pointer */
1773     RtlUnlockHeap(BaseHeap);
1774     return hMem;
1775 }
1776 
1777 /*
1778  * @implemented
1779  */
1780 SIZE_T
1781 WINAPI
LocalShrink(HLOCAL hMem,UINT cbNewSize)1782 LocalShrink(HLOCAL hMem,
1783             UINT cbNewSize)
1784 {
1785     /* Call RTL */
1786     return RtlCompactHeap(BaseHeap, 0);
1787 }
1788 
1789 /*
1790  * @implemented
1791  */
1792 SIZE_T
1793 NTAPI
LocalSize(HLOCAL hMem)1794 LocalSize(HLOCAL hMem)
1795 {
1796     /* This is the same as a Global Size */
1797     return GlobalSize(hMem);
1798 }
1799 
1800 /*
1801  * @implemented
1802  */
1803 BOOL
1804 NTAPI
LocalUnlock(HLOCAL hMem)1805 LocalUnlock(HLOCAL hMem)
1806 {
1807     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1808     BOOL RetVal = TRUE;
1809 
1810     /* Check if this was a simple allocated heap entry */
1811     if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
1812     {
1813        /* Fail, because LocalUnlock is not supported on LMEM_FIXED allocations */
1814        SetLastError(ERROR_NOT_LOCKED);
1815        return FALSE;
1816     }
1817 
1818     /* Otherwise, lock the heap */
1819     RtlLockHeap(BaseHeap);
1820 
1821     /* Get the handle entry */
1822     HandleEntry = BaseHeapGetEntry(hMem);
1823     BASE_TRACE_HANDLE(HandleEntry, hMem);
1824     _SEH2_TRY
1825     {
1826         /* Make sure it's valid */
1827         if (!BaseHeapValidateEntry(HandleEntry))
1828         {
1829             /* It's not, fail */
1830             BASE_TRACE_FAILURE();
1831             SetLastError(ERROR_INVALID_HANDLE);
1832             RetVal = FALSE;
1833         }
1834         else
1835         {
1836             /* Otherwise, decrement lock count, unless we're already at 0*/
1837             if (!HandleEntry->LockCount--)
1838             {
1839                 /* In which case we simply lock it back and fail */
1840                 HandleEntry->LockCount++;
1841                 SetLastError(ERROR_NOT_LOCKED);
1842                 RetVal = FALSE;
1843             }
1844             else if (!HandleEntry->LockCount)
1845             {
1846                 /* Nothing to unlock */
1847                 SetLastError(NO_ERROR);
1848                 RetVal = FALSE;
1849             }
1850         }
1851     }
1852     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1853     {
1854         SetLastError(ERROR_INVALID_PARAMETER);
1855         RetVal = FALSE;
1856     }
1857     _SEH2_END;
1858 
1859     /* All done. Unlock the heap and return the pointer */
1860     RtlUnlockHeap(BaseHeap);
1861     return RetVal;
1862 }
1863 
1864 /* EOF */
1865