Crash Dump Analysis Patterns (Part 273)

C++ Objects may leave virtual function table pointer traces in Execution Residue and, therefore, their adjacent data can be inspected:

0:000> !teb
TEB at 0000000000306000
ExceptionList: 0000000000000000
StackBase: 0000000000150000
StackLimit: 000000000014d000

SubSystemTib: 0000000000000000
FiberData: 0000000000001e00
ArbitraryUserPointer: 0000000000000000
Self: 0000000000306000
EnvironmentPointer: 0000000000000000
ClientId: 0000000000000214 . 00000000000011b0
RpcHandle: 0000000000000000
Tls Storage: 0000000000306058
PEB Address: 0000000000305000
LastErrorValue: 0
LastStatusValue: c0000034
Count Owned Locks: 0
HardErrorMode: 0

0:000> dps 000000000014d000 0000000000150000
00000000`0014d000 00000000`00000000
00000000`0014d008 00000000`00000000
00000000`0014d010 00000000`00000000
00000000`0014d018 00000000`00000000
00000000`0014d020 00000000`00000000
[…]
00000000`0014fe08 00000000`00000000
00000000`0014fe10 00000000`005d4550
00000000`0014fe18 00000000`00000000
00000000`0014fe20 00000000`005cd7e0
00000000`0014fe28 00000000`005cd7e0
00000000`0014fe30 00000000`005cd7e0
00000000`0014fe38 00000001`40017778 ExecutionResidueC__Objects!CObject::`vftable’
00000000`0014fe40 624f206f`6c6c6548
00000000`0014fe48 00000021`7463656a

00000000`0014fe50 00000000`00000000
00000000`0014fe58 00000000`00000000
00000000`0014fe60 00000000`00000000
00000000`0014fe68 00000000`00000000
00000000`0014fe70 00000000`00000000
00000000`0014fe78 00000000`00000000
00000000`0014fe80 00000000`00000000
00000000`0014fe88 00000000`00000000
00000000`0014fe90 00000000`00000000
00000000`0014fe98 00000000`00000000
00000000`0014fea0 00000000`00000000
00000000`0014fea8 00000000`00000000
00000000`0014feb0 00000001`40017778 ExecutionResidueC__Objects!CObject::`vftable’
00000000`0014feb8 624f206f`6c6c6548
00000000`0014fec0 00000021`7463656a

00000000`0014fec8 00000000`00000000
00000000`0014fed0 00000000`00000000
00000000`0014fed8 0000e111`9d4d4b61
[…]

0:000> dps 00000001`40017778
00000001`40017778 00000001`40001040 ExecutionResidueC__Objects!CObject::`scalar deleting destructor’
00000001`40017780 00000001`40001020 ExecutionResidueC__Objects!CObject::foo
00000001`40017788 00000001`40001030 ExecutionResidueC__Objects!CObject::bar
00000001`40017790 600e149f`00000000
00000001`40017798 00000002`00000000
00000001`400177a0 00017c6c`00000069
00000001`400177a8 00000000`00016e6c
00000001`400177b0 00000000`600e149f
00000001`400177b8 00000014`0000000c
00000001`400177c0 00016ed8`00017cd8
00000001`400177c8 600e149f`00000000
00000001`400177d0 0000000d`00000000
00000001`400177d8 00017cec`000002f0
00000001`400177e0 00000000`00016eec
00000001`400177e8 00000000`600e149f
00000001`400177f0 00000000`0000000e

0:000> da 00000000`0014feb8
00000000`0014feb8 “Hello Object!”

0:000> dt ExecutionResidueC__Objects!CObject 00000000`0014feb0
+0×000 __VFN_table : 0×00000001`40017778
+0×008 data : [32] “Hello Object!”

We see that two objects were allocated on the stack. However, finding dynamically allocated objects may require another level of pointer redirection when pointers to such objects are stored on the stack, for example with dpp WinDbg command:

0:000> dpp 000000000014d000 0000000000150000
00000000`0014d000 00000000`00000000
00000000`0014d008 00000000`00000000
00000000`0014d010 00000000`00000000
00000000`0014d018 00000000`00000000
00000000`0014d020 00000000`00000000
[…]
00000000`0014fe08 00000000`00000000
00000000`0014fe10 00000000`005d4550 00000000`005d4560
00000000`0014fe18 00000000`00000000
00000000`0014fe20 00000000`005cd7e0 00000001`40017778 ExecutionResidueC__Objects!CObject::`vftable’
00000000`0014fe28 00000000`005cd7e0 00000001`40017778 ExecutionResidueC__Objects!CObject::`vftable’
00000000`0014fe30 00000000`005cd7e0 00000001`40017778 ExecutionResidueC__Objects!CObject::`vftable’
00000000`0014fe38 00000001`40017778 00000001`40001040 ExecutionResidueC__Objects!CObject::`scalar deleting destructor’
00000000`0014fe40 624f206f`6c6c6548
00000000`0014fe48 00000021`7463656a

00000000`0014fe50 00000000`00000000
00000000`0014fe58 00000000`00000000
00000000`0014fe60 00000000`00000000
00000000`0014fe68 00000000`00000000
00000000`0014fe70 00000000`00000000
00000000`0014fe78 00000000`00000000
00000000`0014fe80 00000000`00000000
00000000`0014fe88 00000000`00000000
00000000`0014fe90 00000000`00000000
00000000`0014fe98 00000000`00000000
00000000`0014fea0 00000000`00000000
00000000`0014fea8 00000000`00000000
00000000`0014feb0 00000001`40017778 00000001`40001040 ExecutionResidueC__Objects!CObject::`scalar deleting destructor’
00000000`0014feb8 624f206f`6c6c6548
00000000`0014fec0 00000021`7463656a

00000000`0014fec8 00000000`00000000
00000000`0014fed0 00000000`00000000
00000000`0014fed8 0000e111`9d4d4b61
[…]

0:000> !address 00000000`005cd7e0

Usage: Heap
Base Address: 00000000`005c0000
End Address: 00000000`005d8000
Region Size: 00000000`00018000 ( 96.000 kB)
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE
Type: 00020000 MEM_PRIVATE
Allocation Base: 00000000`005c0000
Allocation Protect: 00000004 PAGE_READWRITE
More info: heap owning the address: !heap 0×5c0000
More info: heap segment
More info: heap entry containing the address: !heap -x 0×5cd7e0

0:000> dps 00000000`005cd7e0
00000000`005cd7e0 00000001`40017778 ExecutionResidueC__Objects!CObject::`vftable’
00000000`005cd7e8 624f206f`6c6c6548
00000000`005cd7f0 00000021`7463656a

00000000`005cd7f8 00000000`00000000
00000000`005cd800 00000000`00000000
00000000`005cd808 93002500`6c5ec8a3
00000000`005cd810 4f535345`434f5250
00000000`005cd818 54494843`52415f52
00000000`005cd820 413d4552`55544345
00000000`005cd828 00000000`3436444d
00000000`005cd830 00000000`00000000
00000000`005cd838 92002600`6c5bc8a0
00000000`005cd840 576d6172`676f7250
00000000`005cd848 5c3a433d`32333436
00000000`005cd850 206d6172`676f7250
00000000`005cd858 00000073`656c6946

0:000> da 00000000`005cd7e8
00000000`005cd7e8 “Hello Object!”

0:000> dps 00000001`40017778
00000001`40017778 00000001`40001040 ExecutionResidueC__Objects!CObject::`scalar deleting destructor’
00000001`40017780 00000001`40001020 ExecutionResidueC__Objects!CObject::foo
00000001`40017788 00000001`40001030 ExecutionResidueC__Objects!CObject::bar
00000001`40017790 600e149f`00000000
00000001`40017798 00000002`00000000
00000001`400177a0 00017c6c`00000069
00000001`400177a8 00000000`00016e6c
00000001`400177b0 00000000`600e149f
00000001`400177b8 00000014`0000000c
00000001`400177c0 00016ed8`00017cd8
00000001`400177c8 600e149f`00000000
00000001`400177d0 0000000d`00000000
00000001`400177d8 00017cec`000002f0
00000001`400177e0 00000000`00016eec
00000001`400177e8 00000000`600e149f
00000001`400177f0 00000000`0000000e

0:000> dt ExecutionResidueC__Objects!CObject 00000000`005cd7e0
+0×000 __VFN_table : 0×00000001`40017778
+0×008 data : [32] “Hello Object!”

We created a modeling C++ program for better illustration:

struct CObject
{
    virtual ~CObject() {};
    virtual int foo() { return 1; };
    virtual int bar() { return 2; };

    char data[32] = "Hello Object!";
};

int main()
{
    CObject  localObj;
    int      _[20]{};	// padding the stack
    CObject* dynamicObj{new CObject};

    throw CObject();
}

The example memory dump, PDB file, and source code can be downloaded from here.

- Dmitry Vostokov @ DumpAnalysis.org + TraceAnalysis.org -

Comments are closed.