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)
8 #define WIN32_NO_STATUS
12 #if SDBAPI_DEBUG_ALLOC
14 #define TRACE_ALL_FREE_CALLS 1
16 typedef struct SHIM_ALLOC_ENTRY
24 } SHIM_ALLOC_ENTRY
, *PSHIM_ALLOC_ENTRY
;
26 static RTL_CRITICAL_SECTION g_SdbpAllocationLock
;
27 static RTL_AVL_TABLE g_SdbpAllocationTable
;
28 static HANDLE g_PrivAllocationHeap
;
30 static RTL_GENERIC_COMPARE_RESULTS
31 NTAPI
ShimAllocCompareRoutine(_In_ PRTL_AVL_TABLE Table
, _In_ PVOID FirstStruct
, _In_ PVOID SecondStruct
)
33 PVOID First
= ((PSHIM_ALLOC_ENTRY
)FirstStruct
)->Address
;
34 PVOID Second
= ((PSHIM_ALLOC_ENTRY
)SecondStruct
)->Address
;
37 return GenericLessThan
;
38 else if (First
== Second
)
40 return GenericGreaterThan
;
43 static PVOID NTAPI
ShimAllocAllocateRoutine(_In_ PRTL_AVL_TABLE Table
, _In_ CLONG ByteSize
)
45 return RtlAllocateHeap(g_PrivAllocationHeap
, HEAP_ZERO_MEMORY
, ByteSize
);
48 static VOID NTAPI
ShimAllocFreeRoutine(_In_ PRTL_AVL_TABLE Table
, _In_ PVOID Buffer
)
50 RtlFreeHeap(g_PrivAllocationHeap
, 0, Buffer
);
53 void SdbpInsertAllocation(PVOID address
, SIZE_T size
, int line
, const char* file
)
55 SHIM_ALLOC_ENTRY Entry
= {0};
57 Entry
.Address
= address
;
62 RtlEnterCriticalSection(&g_SdbpAllocationLock
);
63 RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable
, &Entry
, sizeof(Entry
), NULL
);
64 RtlLeaveCriticalSection(&g_SdbpAllocationLock
);
67 void SdbpUpdateAllocation(PVOID address
, PVOID newaddress
, SIZE_T size
, int line
, const char* file
)
69 SHIM_ALLOC_ENTRY Lookup
= {0};
70 PSHIM_ALLOC_ENTRY Entry
;
71 Lookup
.Address
= address
;
73 RtlEnterCriticalSection(&g_SdbpAllocationLock
);
74 Entry
= RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable
, &Lookup
);
76 if (address
== newaddress
)
82 Lookup
.Address
= newaddress
;
86 Lookup
.Prev
= address
;
87 RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable
, &Lookup
, sizeof(Lookup
), NULL
);
88 Entry
->Next
= newaddress
;
90 RtlLeaveCriticalSection(&g_SdbpAllocationLock
);
93 static void SdbpPrintSingleAllocation(PSHIM_ALLOC_ENTRY Entry
)
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
);
100 void SdbpRemoveAllocation(PVOID address
, int line
, const char* file
)
102 SHIM_ALLOC_ENTRY Lookup
= {0};
103 PSHIM_ALLOC_ENTRY Entry
;
105 #if TRACE_ALL_FREE_CALLS
106 DbgPrint("\r\n===============\r\n%s(%d): SdbpFree called, tracing alloc:\r\n", file
, line
);
109 Lookup
.Address
= address
;
110 RtlEnterCriticalSection(&g_SdbpAllocationLock
);
111 while (Lookup
.Address
)
113 Entry
= RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable
, &Lookup
);
117 RtlDeleteElementGenericTableAvl(&g_SdbpAllocationTable
, Entry
);
119 #if TRACE_ALL_FREE_CALLS
120 SdbpPrintSingleAllocation(&Lookup
);
122 Lookup
.Address
= Lookup
.Prev
;
126 Lookup
.Address
= NULL
;
129 RtlLeaveCriticalSection(&g_SdbpAllocationLock
);
130 #if TRACE_ALL_FREE_CALLS
131 DbgPrint("===============\r\n");
135 void SdbpDebugHeapInit(HANDLE privateHeapPtr
)
137 g_PrivAllocationHeap
= privateHeapPtr
;
139 RtlInitializeCriticalSection(&g_SdbpAllocationLock
);
140 RtlInitializeGenericTableAvl(&g_SdbpAllocationTable
, ShimAllocCompareRoutine
,
141 ShimAllocAllocateRoutine
, ShimAllocFreeRoutine
, NULL
);
144 void SdbpDebugHeapDeinit(void)
146 if (g_SdbpAllocationTable
.NumberGenericTableElements
!= 0)
148 PSHIM_ALLOC_ENTRY Entry
;
150 DbgPrint("\r\n===============\r\n===============\r\nSdbpHeapDeinit: Dumping leaks\r\n");
151 RtlEnterCriticalSection(&g_SdbpAllocationLock
);
152 Entry
= RtlEnumerateGenericTableAvl(&g_SdbpAllocationTable
, TRUE
);
156 SdbpPrintSingleAllocation(Entry
);
157 Entry
= RtlEnumerateGenericTableAvl(&g_SdbpAllocationTable
, FALSE
);
159 RtlLeaveCriticalSection(&g_SdbpAllocationLock
);
160 DbgPrint("===============\r\n===============\r\n");
163 /*RtlDeleteCriticalSection(&g_SdbpAllocationLock);*/