[APPHELP] Various cleanup tasks
[reactos.git] / reactos / dll / appcompat / apphelp / dbgheap.c
1 /*
2 * Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #define WIN32_NO_STATUS
20 #include "ntndk.h"
21
22
23 #if SDBAPI_DEBUG_ALLOC
24
25 #define TRACE_ALL_FREE_CALLS 1
26
27 typedef struct SHIM_ALLOC_ENTRY
28 {
29 PVOID Address;
30 SIZE_T Size;
31 int Line;
32 const char* File;
33 PVOID Next;
34 PVOID Prev;
35 } SHIM_ALLOC_ENTRY, *PSHIM_ALLOC_ENTRY;
36
37 static RTL_CRITICAL_SECTION g_SdbpAllocationLock;
38 static RTL_AVL_TABLE g_SdbpAllocationTable;
39 static HANDLE g_PrivAllocationHeap;
40
41 static RTL_GENERIC_COMPARE_RESULTS
42 NTAPI ShimAllocCompareRoutine(_In_ PRTL_AVL_TABLE Table, _In_ PVOID FirstStruct, _In_ PVOID SecondStruct)
43 {
44 PVOID First = ((PSHIM_ALLOC_ENTRY)FirstStruct)->Address;
45 PVOID Second = ((PSHIM_ALLOC_ENTRY)SecondStruct)->Address;
46
47 if (First < Second)
48 return GenericLessThan;
49 else if (First == Second)
50 return GenericEqual;
51 return GenericGreaterThan;
52 }
53
54 static PVOID NTAPI ShimAllocAllocateRoutine(_In_ PRTL_AVL_TABLE Table, _In_ CLONG ByteSize)
55 {
56 return RtlAllocateHeap(g_PrivAllocationHeap, HEAP_ZERO_MEMORY, ByteSize);
57 }
58
59 static VOID NTAPI ShimAllocFreeRoutine(_In_ PRTL_AVL_TABLE Table, _In_ PVOID Buffer)
60 {
61 RtlFreeHeap(g_PrivAllocationHeap, 0, Buffer);
62 }
63
64 void SdbpInsertAllocation(PVOID address, SIZE_T size, int line, const char* file)
65 {
66 SHIM_ALLOC_ENTRY Entry = {0};
67
68 Entry.Address = address;
69 Entry.Size = size;
70 Entry.Line = line;
71 Entry.File = file;
72
73 RtlEnterCriticalSection(&g_SdbpAllocationLock);
74 RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable, &Entry, sizeof(Entry), NULL);
75 RtlLeaveCriticalSection(&g_SdbpAllocationLock);
76 }
77
78 void SdbpUpdateAllocation(PVOID address, PVOID newaddress, SIZE_T size, int line, const char* file)
79 {
80 SHIM_ALLOC_ENTRY Lookup = {0};
81 PSHIM_ALLOC_ENTRY Entry;
82 Lookup.Address = address;
83
84 RtlEnterCriticalSection(&g_SdbpAllocationLock);
85 Entry = RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup);
86
87 if (address == newaddress)
88 {
89 Entry->Size = size;
90 }
91 else
92 {
93 Lookup.Address = newaddress;
94 Lookup.Size = size;
95 Lookup.Line = line;
96 Lookup.File = file;
97 Lookup.Prev = address;
98 RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup, sizeof(Lookup), NULL);
99 Entry->Next = newaddress;
100 }
101 RtlLeaveCriticalSection(&g_SdbpAllocationLock);
102 }
103
104 static void SdbpPrintSingleAllocation(PSHIM_ALLOC_ENTRY Entry)
105 {
106 DbgPrint(" > %s(%d): %s%sAlloc( %d ) ==> %p\r\n", Entry->File, Entry->Line,
107 Entry->Next ? "Invalidated " : "", Entry->Prev ? "Re" : "", Entry->Size, Entry->Address);
108
109 }
110
111 void SdbpRemoveAllocation(PVOID address, int line, const char* file)
112 {
113 SHIM_ALLOC_ENTRY Lookup = {0};
114 PSHIM_ALLOC_ENTRY Entry;
115
116 #if TRACE_ALL_FREE_CALLS
117 DbgPrint("\r\n===============\r\n%s(%d): SdbpFree called, tracing alloc:\r\n", file, line);
118 #endif
119
120 Lookup.Address = address;
121 RtlEnterCriticalSection(&g_SdbpAllocationLock);
122 while (Lookup.Address)
123 {
124 Entry = RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup);
125 if (Entry)
126 {
127 Lookup = *Entry;
128 RtlDeleteElementGenericTableAvl(&g_SdbpAllocationTable, Entry);
129
130 #if TRACE_ALL_FREE_CALLS
131 SdbpPrintSingleAllocation(&Lookup);
132 #endif
133 Lookup.Address = Lookup.Prev;
134 }
135 else
136 {
137 Lookup.Address = NULL;
138 }
139 }
140 RtlLeaveCriticalSection(&g_SdbpAllocationLock);
141 #if TRACE_ALL_FREE_CALLS
142 DbgPrint("===============\r\n");
143 #endif
144 }
145
146 void SdbpDebugHeapInit(HANDLE privateHeapPtr)
147 {
148 g_PrivAllocationHeap = privateHeapPtr;
149
150 RtlInitializeCriticalSection(&g_SdbpAllocationLock);
151 RtlInitializeGenericTableAvl(&g_SdbpAllocationTable, ShimAllocCompareRoutine,
152 ShimAllocAllocateRoutine, ShimAllocFreeRoutine, NULL);
153 }
154
155 void SdbpDebugHeapDeinit(void)
156 {
157 if (g_SdbpAllocationTable.NumberGenericTableElements != 0)
158 {
159 PSHIM_ALLOC_ENTRY Entry;
160
161 DbgPrint("\r\n===============\r\n===============\r\nSdbpHeapDeinit: Dumping leaks\r\n");
162 RtlEnterCriticalSection(&g_SdbpAllocationLock);
163 Entry = RtlEnumerateGenericTableAvl(&g_SdbpAllocationTable, TRUE);
164
165 while (Entry)
166 {
167 SdbpPrintSingleAllocation(Entry);
168 Entry = RtlEnumerateGenericTableAvl(&g_SdbpAllocationTable, FALSE);
169 }
170 RtlLeaveCriticalSection(&g_SdbpAllocationLock);
171 DbgPrint("===============\r\n===============\r\n");
172 }
173 /*__debugbreak();*/
174 /*RtlDeleteCriticalSection(&g_SdbpAllocationLock);*/
175 }
176
177 #endif