Search code examples
.netvisual-studiostack-overflowwindbgdump

How to read the parent thread or parent function of a thread or call stack


I'm trying to decypher a StackOverflowException crashdump.

The call stack, as shown in Visual Studio, looks as follows:

ntdll.dll!RtlAllocateHeap()
[Inline Frame] combase.dll!CRetailMalloc_Alloc(IMalloc *) Line 640
combase.dll!CoTaskMemAlloc(unsigned __int64 stcb) Line 459
shell32.dll!CFSFolder::_InitFolder()
shell32.dll!CFSFolder::_Bind()
shell32.dll!CFSFolder::BindToObject()
shell32.dll!CRegFolder::BindToObject()
shell32.dll!CRegFolder::BindToObject()
shell32.dll!SHBindToObject()
shell32.dll!SHGetAttributesWithBindCtx()
shell32.dll!CShellLink::_IsTargetAnotherLink()
shell32.dll!CShellLink::_LoadIDList()
shell32.dll!CShellLink::_LoadFromStream()
shell32.dll!CShellLink::_LoadFromFile()
shell32.dll!CShellLink::Load(unsigned short const *,unsigned long)

This seems not very interesting. In Windbg however, the command ~kb gives some more information:

0:040> ~kb
 # RetAddr           : Args to Child                                                           : Call Site
00 00007ffc`9d5f184a : 00000000`000001b0 00000000`00000002 00000000`00000002 00000000`1e492250 : ntdll!RtlAllocateHeap+0xd2
01 (Inline Function) : --------`-------- --------`-------- --------`-------- --------`-------- : combase!CRetailMalloc_Alloc+0x12 [d:\blue\com\combase\class\memapi.cxx @ 640] 
02 00007ffc`9e3dd4fe : 00000000`000001ad 00000000`00000000 00000000`000001ad 00007ffc`9fa30d67 : combase!CoTaskMemAlloc+0x3a [d:\blue\com\combase\class\memapi.cxx @ 459] 
03 00007ffc`9e3dcf2d : 00007ffc`9e561188 00000000`00000000 00000000`1a6053e0 00007ffc`9e561188 : shell32!CFSFolder::_InitFolder+0xd2
04 00007ffc`9e3dc685 : 00000000`1b803198 00007ffc`9e34203d 00000000`1a1a8580 00007ffc`9e3420c0 : shell32!CFSFolder::_Bind+0x9d1
05 00007ffc`9e3de676 : 00000000`1e7c4af4 00007ffc`9e561188 00000000`00000000 00007ffc`9fa30d67 : shell32!CFSFolder::BindToObject+0x664
06 00007ffc`9e3db94c : 00007ffc`9d5f1860 00430072`006f0046 00000000`00000003 ffffffff`fffffffe : shell32!CRegFolder::BindToObject+0x8bd
07 00007ffc`9e3dafda : 00000000`1e638820 00000000`00000000 00000000`1e7c4ae0 00007ffc`9e3dff07 : shell32!CRegFolder::BindToObject+0x687
08 00007ffc`9e40c041 : 00000000`00000000 00000000`1e80c2a0 00000000`00000000 00006567`8ccde5e5 : shell32!SHBindToObject+0x11d
09 00007ffc`9e408a7b : 00000000`1e638820 00000000`1e7c4ae0 00000000`00000001 00000000`00410000 : shell32!SHGetAttributesWithBindCtx+0x1a0
0a 00007ffc`9e40958f : 00000000`00000000 00000000`00000000 00000000`1a1a9630 00000000`00000000 : shell32!CShellLink::_IsTargetAnotherLink+0x7b
0b 00007ffc`9e40886b : 00000000`00000048 00000000`1e6389e0 00000000`00000000 00000000`1a1a96a0 : shell32!CShellLink::_LoadIDList+0x4b
0c 00007ffc`9e40b3f9 : 00000000`00000000 00000000`1e638820 00000000`00000000 00000000`80000000 : shell32!CShellLink::_LoadFromStream+0x2da
0d 00007ffc`9e40b359 : 00007ffc`8d49c3d9 00000000`1a1a99f8 00000000`00003201 00000000`1f95b1e4 : shell32!CShellLink::_LoadFromFile+0x8f
0e 00007ffc`2ea805f9 : 00000000`00000000 00000000`1a1a9d20 00000000`00000000 00000000`1f95b280 : shell32!CShellLink::Load+0x25
0f 00007ffc`2ea80479 : 00000000`1f95b280 00000000`00000000 00000000`1f95b1d8 00000000`00000000 : 0x00007ffc`2ea805f9
10 00007ffc`2ea8036c : 00000000`00000000 00000000`00000000 00000000`1f95b1b8 00000000`022c55e8 : 0x00007ffc`2ea80479
11 00007ffc`2ea802cd : 00000000`1f95b1d8 00007ffc`2e5d4a3c 00000000`00000000 00000000`022c55e8 : 0x00007ffc`2ea8036c
12 00007ffc`2ea7eae2 : 00000000`04233f90 00009ebd`de3821dd 00000000`00000003 00000000`00000003 : 0x00007ffc`2ea802cd
13 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f9571c0 00000000`00000003 : 0x00007ffc`2ea7eae2
14 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f94ec10 00000000`00000003 : 0x00007ffc`2ea7ee80
15 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f946660 00000000`00000003 : 0x00007ffc`2ea7ee80
16 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f93e0b0 00000000`00000003 : 0x00007ffc`2ea7ee80
17 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f935b00 00000000`00000003 : 0x00007ffc`2ea7ee80
...
ff 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f744808 00000000`00000003 : 0x00007ffc`2ea7ee80

This seems in line with the StackOverflowException (too many calls in the callstack): indeed the function at memory address 0x00007ffc'2ea7ee80 - I replaced the backtick by a single quote for formatting reasons - is constantly calling itself.

Now the question: how can I know which function this is or which is the parent thread?

As for Windbg: when I click on the last entry (ff, DMS is enabled), I see the following:

0:040> dx Debugger.Sessions[0].Processes[10912].Threads[5268].Stack.Frames[255].SwitchTo();dv /t /v
Debugger.Sessions[0].Processes[10912].Threads[5268].Stack.Frames[255].SwitchTo()
Unable to enumerate locals, Win32 error 0n318
Private symbols (symbols.pri) are required for locals.
Type ".hh dbgerr005" for details

For your information: in Visual Studio's Parallel Stacks window, I don't see the thread, referring to this one.

Does anybody have an idea?
Thanks in advance


Solution

  • A bare address in the callstack means the code is not in any loaded module.

    This could be for a few reasons:

    1. The code could have been generated at runtime, as is the case for a JIT.
    2. The code may reside in a module that has been unloaded.
    3. The callstack may be corrupt.

    When .NET is involved, it's usually the first reason -- it's JIT'd code. This is pretty easy to check using the SOS debugger extension.

    First load the extension with .loadby sos clr then check the relevant instruction pointer or return address using !ip2md 0x00007ff`c2ea802cd.

    If it is JIT'd .NET code, then you'll probably want to familiarize yourself with the other commands provided by the the SOS extension to debug the issue.

    As Lieven Keersmaekers mentioned, you can check for an unloaded module (reason #2) using the lm command and looking for unloaded modules.

    And you can get some general information about the memory address using: !address 0x00007ff`c2ea802cd. If the page doesn't have PAGE_EXECUTE protections or something similar, I'd expect that the callstack is bogus (reason #3).

    Note: There are other JIT runtimes around. They are quite common for virtual machines, scripting languages, and even some libraries like regex engines. These runtimes tend not to provide debugger extensions so, if you ever suspect one is being used, you may have to look for a tool for that specific runtime.