xref: /reactos/dll/appcompat/apphelp/dbgheap.c (revision c2c66aff)
1 /*
2  * PROJECT:     ReactOS Application compatibility module
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     SDB Debug heap functionality
5  * COPYRIGHT:   Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #define WIN32_NO_STATUS
9 #include "ntndk.h"
10 
11 
12 #if SDBAPI_DEBUG_ALLOC
13 
14 #define TRACE_ALL_FREE_CALLS    1
15 
16 typedef struct SHIM_ALLOC_ENTRY
17 {
18     PVOID Address;
19     SIZE_T Size;
20     int Line;
21     const char* File;
22     PVOID Next;
23     PVOID Prev;
24 } SHIM_ALLOC_ENTRY, *PSHIM_ALLOC_ENTRY;
25 
26 static RTL_CRITICAL_SECTION g_SdbpAllocationLock;
27 static RTL_AVL_TABLE g_SdbpAllocationTable;
28 static HANDLE g_PrivAllocationHeap;
29 
30 static RTL_GENERIC_COMPARE_RESULTS
ShimAllocCompareRoutine(_In_ PRTL_AVL_TABLE Table,_In_ PVOID FirstStruct,_In_ PVOID SecondStruct)31 NTAPI ShimAllocCompareRoutine(_In_ PRTL_AVL_TABLE Table, _In_ PVOID FirstStruct, _In_ PVOID SecondStruct)
32 {
33     PVOID First = ((PSHIM_ALLOC_ENTRY)FirstStruct)->Address;
34     PVOID Second = ((PSHIM_ALLOC_ENTRY)SecondStruct)->Address;
35 
36     if (First < Second)
37         return GenericLessThan;
38     else if (First == Second)
39         return GenericEqual;
40     return GenericGreaterThan;
41 }
42 
ShimAllocAllocateRoutine(_In_ PRTL_AVL_TABLE Table,_In_ CLONG ByteSize)43 static PVOID NTAPI ShimAllocAllocateRoutine(_In_ PRTL_AVL_TABLE Table, _In_ CLONG ByteSize)
44 {
45     return RtlAllocateHeap(g_PrivAllocationHeap, HEAP_ZERO_MEMORY, ByteSize);
46 }
47 
ShimAllocFreeRoutine(_In_ PRTL_AVL_TABLE Table,_In_ PVOID Buffer)48 static VOID NTAPI ShimAllocFreeRoutine(_In_ PRTL_AVL_TABLE Table, _In_ PVOID Buffer)
49 {
50     RtlFreeHeap(g_PrivAllocationHeap, 0, Buffer);
51 }
52 
SdbpInsertAllocation(PVOID address,SIZE_T size,int line,const char * file)53 void SdbpInsertAllocation(PVOID address, SIZE_T size, int line, const char* file)
54 {
55     SHIM_ALLOC_ENTRY Entry = {0};
56 
57     Entry.Address = address;
58     Entry.Size = size;
59     Entry.Line = line;
60     Entry.File = file;
61 
62     RtlEnterCriticalSection(&g_SdbpAllocationLock);
63     RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable, &Entry, sizeof(Entry), NULL);
64     RtlLeaveCriticalSection(&g_SdbpAllocationLock);
65 }
66 
SdbpUpdateAllocation(PVOID address,PVOID newaddress,SIZE_T size,int line,const char * file)67 void SdbpUpdateAllocation(PVOID address, PVOID newaddress, SIZE_T size, int line, const char* file)
68 {
69     SHIM_ALLOC_ENTRY Lookup = {0};
70     PSHIM_ALLOC_ENTRY Entry;
71     Lookup.Address = address;
72 
73     RtlEnterCriticalSection(&g_SdbpAllocationLock);
74     Entry = RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup);
75 
76     if (address == newaddress)
77     {
78         Entry->Size = size;
79     }
80     else
81     {
82         Lookup.Address = newaddress;
83         Lookup.Size = size;
84         Lookup.Line = line;
85         Lookup.File = file;
86         Lookup.Prev = address;
87         RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup, sizeof(Lookup), NULL);
88         Entry->Next = newaddress;
89     }
90     RtlLeaveCriticalSection(&g_SdbpAllocationLock);
91 }
92 
SdbpPrintSingleAllocation(PSHIM_ALLOC_ENTRY Entry)93 static void SdbpPrintSingleAllocation(PSHIM_ALLOC_ENTRY Entry)
94 {
95     DbgPrint(" > %s(%d): %s%sAlloc( %d ) ==> %p\r\n", Entry->File, Entry->Line,
96              Entry->Next ? "Invalidated " : "", Entry->Prev ? "Re" : "", Entry->Size, Entry->Address);
97 
98 }
99 
SdbpRemoveAllocation(PVOID address,int line,const char * file)100 void SdbpRemoveAllocation(PVOID address, int line, const char* file)
101 {
102     SHIM_ALLOC_ENTRY Lookup = {0};
103     PSHIM_ALLOC_ENTRY Entry;
104 
105 #if TRACE_ALL_FREE_CALLS
106     DbgPrint("\r\n===============\r\n%s(%d): SdbpFree called, tracing alloc:\r\n", file, line);
107 #endif
108 
109     Lookup.Address = address;
110     RtlEnterCriticalSection(&g_SdbpAllocationLock);
111     while (Lookup.Address)
112     {
113         Entry = RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup);
114         if (Entry)
115         {
116             Lookup = *Entry;
117             RtlDeleteElementGenericTableAvl(&g_SdbpAllocationTable, Entry);
118 
119 #if TRACE_ALL_FREE_CALLS
120             SdbpPrintSingleAllocation(&Lookup);
121 #endif
122             Lookup.Address = Lookup.Prev;
123         }
124         else
125         {
126             Lookup.Address = NULL;
127         }
128     }
129     RtlLeaveCriticalSection(&g_SdbpAllocationLock);
130 #if TRACE_ALL_FREE_CALLS
131     DbgPrint("===============\r\n");
132 #endif
133 }
134 
SdbpDebugHeapInit(HANDLE privateHeapPtr)135 void SdbpDebugHeapInit(HANDLE privateHeapPtr)
136 {
137     g_PrivAllocationHeap = privateHeapPtr;
138 
139     RtlInitializeCriticalSection(&g_SdbpAllocationLock);
140     RtlInitializeGenericTableAvl(&g_SdbpAllocationTable, ShimAllocCompareRoutine,
141         ShimAllocAllocateRoutine, ShimAllocFreeRoutine, NULL);
142 }
143 
SdbpDebugHeapDeinit(void)144 void SdbpDebugHeapDeinit(void)
145 {
146     if (g_SdbpAllocationTable.NumberGenericTableElements != 0)
147     {
148         PSHIM_ALLOC_ENTRY Entry;
149 
150         DbgPrint("\r\n===============\r\n===============\r\nSdbpHeapDeinit: Dumping leaks\r\n");
151         RtlEnterCriticalSection(&g_SdbpAllocationLock);
152         Entry = RtlEnumerateGenericTableAvl(&g_SdbpAllocationTable, TRUE);
153 
154         while (Entry)
155         {
156             SdbpPrintSingleAllocation(Entry);
157             Entry = RtlEnumerateGenericTableAvl(&g_SdbpAllocationTable, FALSE);
158         }
159         RtlLeaveCriticalSection(&g_SdbpAllocationLock);
160         DbgPrint("===============\r\n===============\r\n");
161     }
162     /*__debugbreak();*/
163     /*RtlDeleteCriticalSection(&g_SdbpAllocationLock);*/
164 }
165 
166 #endif
167