8

I'm debugging a potential GDI Handle Leak. Thanks to @Alois Kraus, there is a WinDbg script which performs a handle count.

From my debugging sessions, especially for .NET, I find that usually, it's better to have 32-bit dumps of 32-bit processes and 64-bit dumps of 64-bit processes.

Unfortunately, with 2 crash dumps I received, the script does not work. Looking deeper into it, I found out that the GdiSharedHandleTable is null in those dumps:

0:000> dt ntdll!_PEB GdiSharedHandleTable @$peb
   +0x094 GdiSharedHandleTable : (null) 

Now, on his website, Alois mentions

Important: If you are running on a 64 bit OS you need to attach the 64-bit Windbg even if you debug a 32-bit application!

Unfortunately, using 64-bit WinDbg on the 32-bit crash dump does not help. The result is still the same.

Now here's a theory:

  • some DLLs in a 32-bit process are 64 bit DLLs (see Windows Internals 5, Chapter 3, "System mechanisms," page 211)
  • ntdll is one of them (it is loaded twice, in the 64-bit version and the 32-bit version)
  • While GDI objects are user objects (and not kernel objects), they still need to be painted, etc. by the OS. Therefore it could be required that they are managed in the WOW64 layer
  • This would mean that I have to have a WOW64 crash dump to make it work

So my question is: do I have the seldom case here that I need a WOW64 crash dump? A more detailed explanation of my theory would be great. If there's a good explanation in some book already, a reference to the chapter is enough. I'll buy it if I don't have it yet.

Community
  • 1
  • 1
Thomas Weller
  • 43,638
  • 16
  • 101
  • 185

2 Answers2

2

For a GDI handle dump you need to take 64 bit dump even if it is a 32 bit process on a Win64 machine. If you take a 32 bit dump on a 64 bit machine the pointer to the GDI Shared handle table is null. It looks like this information is only captured for a 64 bit dump.

That makes sense since you would need to deal with 64 bit pointers in a 32 bit process because the GDI handle table part of your process is mapped from the kernel space into your address space. I guess that was done to stay consistent with the rule that a 32 bit process should only contain pointers of the same bitness.

Alois Kraus
  • 12,323
  • 32
  • 57
2

if the dump was taken before the process reached its WinMain / Main /WinmainCrtStartup / Etc
that is if the initialization code isn't run then GdiSharedHandleTable can be null

It is not the case for a dump that crashed during its normal operation but it is a point to note
for example if you started calc.exe in windbg and check for GdiSharedHandleTable when it was on the first system break GdiSharedHandle can be NULL
but will be filled if you set a break on @$exentry or calc!WinMain

the script that generated this output has been posted as an answer to linked thread

0:000> dd  @@c++(@$Peb->GdiSharedHandleTable)

00000000  ???????? ???????? ???????? ????????
00000010  ???????? ???????? ???????? ????????
00000020  ???????? ???????? ???????? ????????
00000030  ???????? ???????? ???????? ????????
00000040  ???????? ???????? ???????? ????????
00000050  ???????? ???????? ???????? ????????
00000060  ???????? ???????? ???????? ????????
00000070  ???????? ???????? ???????? ????????

0:000> g calc!WinMain

calc!WinMain:
00591635 8bff            mov     edi,edi

0:000> dd  @@c++(@$Peb->GdiSharedHandleTable)

00470000  00000000 00000000 40000000 00000000
00470010  00000000 00000000 00000000 00000000
00470020  00000000 00000000 00000000 00000000
00470030  00000000 00000000 00000000 00000000
00470040  00000000 00000000 00000000 00000000
00470050  00000000 00000000 00000000 00000000
00470060  00000000 00000000 00000000 00000000
00470070  00000000 00000000 00000000 00000000

0:000> $$>a< c:\wdscr\dumpgdi.txt

gdioffs Kaddr     Pid      Count    Handle  Type      Tname    IsLive    UAddr    
00472b30 fe6b5728 00000ca4 00000000 0d0102b3 00000001 DC       00000040 000e0cb0
00472be0 fdf73da8 00000ca4 00000000 420502be 00000005 Bitmap   00000040 00000000
004737b0 fddac108 00000ca4 00000000 9605037b 00000005 Bitmap   00000040 00000000
00474030 fe76eda8 00000ca4 00000000 eb050403 00000005 Bitmap   00000040 00000000
00474c90 fddde008 00000ca4 00000000 d70a04c9 0000000a Font     00000040 001fb1e8
0047ab80 fddab008 00000ca4 00000000 ba050ab8 00000005 Bitmap   00000040 00000000
0047f270 fddbcda8 00000ca4 00000000 16050f27 00000005 Bitmap   00000040 00000000
0047fef0 fdee4da8 00000ca4 00000000 cd050fef 00000005 Bitmap   00000040 00000000
004809f0 fe72eda8 00000ca4 00000000 3405109f 00000005 Bitmap   00000040 00000000
00480e50 fdda5aa8 00000ca4 00000000 0e0510e5 00000005 Bitmap   00000040 00000000
00481cf0 ffb0fda8 00000ca4 00000000 df0511cf 00000005 Bitmap   00000040 00000000
00481d70 fddb0da8 00000ca4 00000000 930511d7 00000005 Bitmap   00000040 00000000
00482020 ff4a1da8 00000ca4 00000000 d4051202 00000005 Bitmap   00000040 00000000
00482060 fddd4008 00000ca4 00000000 39051206 00000005 Bitmap   00000040 00000000
00482170 fddb6008 00000ca4 00000000 20051217 00000005 Bitmap   00000040 00000000
00483140 ff4a0008 00000ca4 00000000 4e051314 00000005 Bitmap   00000040 00000000
00483870 ff427980 00000ca4 00000000 6d051387 00000005 Bitmap   00000040 00000000
00483d80 fe7d04b0 00000ca4 00000000 bd0513d8 00000005 Bitmap   00000040 00000000
00484620 ff437eb8 00000ca4 00000000 0d101462 00000010 Brush    00000040 000f0fd8
004846a0 fddc2da8 00000ca4 00000000 d305146a 00000005 Bitmap   00000040 00000000
00484b80 fdf1a728 00000ca4 00000000 530114b8 00000001 DC       00000040 000e0ae0


Gdi Handles for C:\Windows\system32\calc.exe
Total Gdi Handles = 21
DC       = 2
Font     = 0
Region   = 17
Brush    = 0
Bitmap   = 1
Pen      = 1
Pallete  = 0
Unknpown = 0

enter image description here

Community
  • 1
  • 1
blabb
  • 7,524
  • 1
  • 14
  • 23
  • Which calc did you use? On Win 7 x64, calc is 64 bit. In your debug session, `dd @@c++(@$Peb->GdiSharedHandleTable)` returns `00000000 00000000`, so it's null and the script should not work. However, when you run the script, it returns correct results. This seems to be a contradiction to me. – Thomas Weller Dec 05 '16 at 10:46
  • Sorry i am unable to understand what contradiction you see i do dd poi() 2 times first when app is at systembp and second when app is at its winmain first time table is null and second time table points to valid memory – blabb Dec 06 '16 at 06:01