3 #define KeRosDumpStackFrames(Frames, Count) KdSystemDebugControl('DsoR', (PVOID)Frames, Count, NULL, 0, NULL, KernelMode)
4 NTSYSAPI ULONG APIENTRY
RtlWalkFrameChain(OUT PVOID
*Callers
, IN ULONG Count
, IN ULONG Flags
);
6 static int leak_reported
= 0;
7 #define GDI_STACK_LEVELS 12
8 static ULONG GDIHandleAllocator
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
9 static ULONG GDIHandleLocker
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
10 static ULONG GDIHandleShareLocker
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
11 static ULONG GDIHandleDeleter
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
12 struct DbgOpenGDIHandle
18 static struct DbgOpenGDIHandle h
[H
];
20 void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable
)
22 int i
, n
= 0, j
, k
, J
;
26 DPRINT1("gdi handle abusers already reported!\n");
31 DPRINT1("reporting gdi handle abusers:\n");
33 /* step through GDI handle table and find out who our culprit is... */
34 for (i
= RESERVE_ENTRIES_COUNT
; i
< GDI_HANDLE_COUNT
; i
++)
36 for (j
= 0; j
< n
; j
++)
40 for (k
= 0; k
< GDI_STACK_LEVELS
; k
++)
42 if (GDIHandleAllocator
[i
][k
]
43 != GDIHandleAllocator
[J
][k
])
66 /* bubble sort time! weeeeee!! */
67 for (i
= 0; i
< n
-1; i
++)
69 if (h
[i
].count
< h
[i
+1].count
)
71 struct DbgOpenGDIHandle t
;
75 while (j
> 0 && h
[j
-1].count
< t
.count
)
80 /* print the worst offenders... */
81 DbgPrint("Worst GDI Handle leak offenders (out of %i unique locations):\n", n
);
82 for (i
= 0; i
< n
&& h
[i
].count
> 1; i
++)
84 /* Print out the allocation count */
85 DbgPrint(" %i allocs: ", h
[i
].count
);
88 KeRosDumpStackFrames(GDIHandleAllocator
[h
[i
].idx
], GDI_STACK_LEVELS
);
90 /* Print new line for better readability */
93 if (i
< n
&& h
[i
].count
== 1)
94 DbgPrint("(list terminated - the remaining entries have 1 allocation only)\n");
98 CaptureStackBackTace(PVOID
* pFrames
, ULONG nFramesToCapture
)
102 memset(pFrames
, 0x00, (nFramesToCapture
+ 1) * sizeof(PVOID
));
104 nFrameCount
= RtlCaptureStackBackTrace(1, nFramesToCapture
, pFrames
, NULL
);
106 if (nFrameCount
< nFramesToCapture
)
108 nFrameCount
+= RtlWalkFrameChain(pFrames
+ nFrameCount
, nFramesToCapture
- nFrameCount
, 1);
115 GdiDbgHTIntegrityCheck()
117 ULONG i
, nDeleted
= 0, nFree
= 0, nUsed
= 0;
118 PGDI_TABLE_ENTRY pEntry
;
121 KeEnterCriticalRegion();
123 /* FIXME: check reserved entries */
125 /* Now go through the deleted objects */
126 i
= GdiHandleTable
->FirstFree
;
129 pEntry
= &GdiHandleTable
->Entries
[i
];
134 /* Check the entry */
135 if ((pEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
138 DPRINT1("Deleted Entry has a type != 0\n");
140 if ((ULONG_PTR
)pEntry
->KernelData
>= GDI_HANDLE_COUNT
)
143 DPRINT1("Deleted entries KernelPointer too big\n");
145 if (pEntry
->UserData
!= NULL
)
148 DPRINT1("Deleted entry has UserData != 0\n");
150 if (pEntry
->ProcessId
!= 0)
153 DPRINT1("Deleted entry has ProcessId != 0\n");
156 i
= (ULONG_PTR
)pEntry
->KernelData
;
161 pEntry
= &GdiHandleTable
->Entries
[i
];
165 for (i
= GdiHandleTable
->FirstUnused
;
166 i
< GDI_HANDLE_COUNT
;
169 pEntry
= &GdiHandleTable
->Entries
[i
];
171 if ((pEntry
->Type
) != 0)
174 DPRINT1("Free Entry has a type != 0\n");
176 if ((ULONG_PTR
)pEntry
->KernelData
!= 0)
179 DPRINT1("Free entries KernelPointer != 0\n");
181 if (pEntry
->UserData
!= NULL
)
184 DPRINT1("Free entry has UserData != 0\n");
186 if (pEntry
->ProcessId
!= 0)
189 DPRINT1("Free entry has ProcessId != 0\n");
194 for (i
= RESERVE_ENTRIES_COUNT
; i
< GDI_HANDLE_COUNT
; i
++)
199 pEntry
= &GdiHandleTable
->Entries
[i
];
201 Handle
= (HGDIOBJ
)((Type
<< GDI_ENTRY_UPPER_SHIFT
) + i
);
203 if (Type
& GDI_ENTRY_BASETYPE_MASK
)
205 if (pEntry
->KernelData
== NULL
)
208 DPRINT1("Used entry has KernelData == 0\n");
210 if (pEntry
->KernelData
<= MmHighestUserAddress
)
213 DPRINT1("Used entry invalid KernelData\n");
215 if (((POBJ
)(pEntry
->KernelData
))->hHmgr
!= Handle
)
218 DPRINT1("Used entry %ld, has invalid hHmg %p (expected: %p)\n",
219 i
, ((POBJ
)(pEntry
->KernelData
))->hHmgr
, Handle
);
225 if (RESERVE_ENTRIES_COUNT
+ nDeleted
+ nFree
+ nUsed
!= GDI_HANDLE_COUNT
)
228 DPRINT1("Number of all entries incorrect: RESERVE_ENTRIES_COUNT = %ld, nDeleted = %ld, nFree = %ld, nUsed = %ld\n",
229 RESERVE_ENTRIES_COUNT
, nDeleted
, nFree
, nUsed
);
232 KeLeaveCriticalRegion();
237 #define GDIDBG_TRACECALLER() \
238 DPRINT1("-> called from:\n"); \
239 KeRosDumpStackFrames(NULL, 20);
240 #define GDIDBG_TRACEALLOCATOR(handle) \
241 DPRINT1("-> allocated from:\n"); \
242 KeRosDumpStackFrames(GDIHandleAllocator[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
243 #define GDIDBG_TRACELOCKER(handle) \
244 DPRINT1("-> locked from:\n"); \
245 KeRosDumpStackFrames(GDIHandleLocker[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
246 #define GDIDBG_TRACESHARELOCKER(handle) \
247 DPRINT1("-> locked from:\n"); \
248 KeRosDumpStackFrames(GDIHandleShareLocker[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
249 #define GDIDBG_TRACEDELETER(handle) \
250 DPRINT1("-> deleted from:\n"); \
251 KeRosDumpStackFrames(GDIHandleDeleter[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
252 #define GDIDBG_CAPTUREALLOCATOR(handle) \
253 CaptureStackBackTace((PVOID*)GDIHandleAllocator[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
254 #define GDIDBG_CAPTURELOCKER(handle) \
255 CaptureStackBackTace((PVOID*)GDIHandleLocker[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
256 #define GDIDBG_CAPTURESHARELOCKER(handle) \
257 CaptureStackBackTace((PVOID*)GDIHandleShareLocker[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
258 #define GDIDBG_CAPTUREDELETER(handle) \
259 CaptureStackBackTace((PVOID*)GDIHandleDeleter[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
260 #define GDIDBG_DUMPHANDLETABLE() \
261 IntDumpHandleTable(GdiHandleTable)
262 #define GDIDBG_INITLOOPTRACE() \
264 #define GDIDBG_TRACELOOP(Handle, PrevThread, Thread) \
265 if ((++Attempts % 20) == 0) \
267 DPRINT1("[%d] Handle 0x%p Locked by 0x%x (we're 0x%x)\n", Attempts, Handle, PrevThread, Thread); \
272 GDIOBJ_IncrementShareCount(POBJ Object
)
274 INT cLocks
= InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
275 GDIDBG_CAPTURESHARELOCKER(Object
->hHmgr
);
282 #define GDIDBG_TRACECALLER()
283 #define GDIDBG_TRACEALLOCATOR(index)
284 #define GDIDBG_TRACELOCKER(index)
285 #define GDIDBG_TRACESHARELOCKER(index)
286 #define GDIDBG_CAPTUREALLOCATOR(index)
287 #define GDIDBG_CAPTURELOCKER(index)
288 #define GDIDBG_CAPTURESHARELOCKER(index)
289 #define GDIDBG_CAPTUREDELETER(handle)
290 #define GDIDBG_DUMPHANDLETABLE()
291 #define GDIDBG_INITLOOPTRACE()
292 #define GDIDBG_TRACELOOP(Handle, PrevThread, Thread)
293 #define GDIDBG_TRACEDELETER(handle)
295 #endif /* GDI_DEBUG */