First thing read thru this text, it often provides good enough information. Here windbg is warning you stored exception information in
Generally you start with either
.excr command or start with
!analyze -v extension.
.clscommand clears the window if gets too cluttered
!analyze -v dumps a lot of text, lets take it step by step:
Here is clearly highlighted that
line 15 has expection information.
Lines 16-23 have register contents dumped. These are often helpful to make sense of what was being executed at the moment of error. With some basic assembly knowledge and patterns of code generated it can help pin-point the root cause in mins.
Line 24 points to the last stack-frame:
ucrtbase!abort+0x4e:, the error was thrown from function
ucrtbase and offset
0x4e in that fn. The executed at that line is
int 29h, which is an instruction defined by
analyze extension tries to classify the error per MS classification system. Here it listed error as
FATAL_APP_EXIT, however the error code
0xc0000409 specified is not really what happened with this application. This is a case of unhandled exception from a background thread, eventually crashing the process not a stack-based buffer overflow.
I have posted the entire output of this
analyze -v command here on gist.github.com. Towards the end of
analyze output it prints the call-stack for the thread from which the error was cached in
.excr. However that is just 1 thread.
To further check what is going on, I am going to query threads in this dump with command
0:009> ~ 0 Id: 62c.1084 Suspend: 1 Teb: 00000073`bacb7000 Unfrozen 1 Id: 62c.3a48 Suspend: 1 Teb: 00000073`bacb9000 Unfrozen 2 Id: 62c.2828 Suspend: 1 Teb: 00000073`bacbb000 Unfrozen 3 Id: 62c.2850 Suspend: 1 Teb: 00000073`bacbd000 Unfrozen 4 Id: 62c.2b28 Suspend: 1 Teb: 00000073`bacbf000 Unfrozen 5 Id: 62c.41a0 Suspend: 1 Teb: 00000073`bacc1000 Unfrozen 6 Id: 62c.40c Suspend: 0 Teb: 00000073`bacc3000 Unfrozen 7 Id: 62c.854 Suspend: 0 Teb: 00000073`bacc5000 Unfrozen 8 Id: 62c.2ef4 Suspend: 0 Teb: 00000073`bacc7000 Unfrozen . 9 Id: 62c.2a10 Suspend: 0 Teb: 00000073`bacc9000 Unfrozen 10 Id: 62c.1a58 Suspend: 0 Teb: 00000073`baccb000 Unfrozen 11 Id: 62c.890 Suspend: 0 Teb: 00000073`baccd000 Unfrozen 12 Id: 62c.17f0 Suspend: 0 Teb: 00000073`baccf000 Unfrozen
62c is process-id and
3a48 and so on are thread-ids.
to check stack of thread
3a48 Thread#1, execute command:
0:009> ~1 KB # RetAddr : Args to Child : Call Site 00 00007ffb`5c9b4060 : 00000000`00000000 00000000`00000000 000001f1`480639d0 00000000`00000002 : ntdll!NtWaitForWorkViaWorkerFactory+0x14 01 00007ffb`5afc7bd4 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!TppWorkerThread+0x300 02 00007ffb`5c9eced1 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0x14 03 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21
To check stack of (upto 25 frames):
- all threads, execute command:
~* KB 25
- thread that caused exception:
~# K 25
~# kP 25provides with lot more information to browse thru
Kcommand takes various parameters and prints stack with various level of details. I have found kP to be quite verbose and browsable, but for blog posts
KCoption works best
Looking at call-stack:
0:009> ~# KC 25 # Call Site 00 ucrtbase!abort 01 ucrtbase!terminate 02 VCRUNTIME140!FindHandler<__FrameHandler3> 03 VCRUNTIME140!__InternalCxxFrameHandler<__FrameHandler3> 04 VCRUNTIME140!__CxxFrameHandler3 05 ntdll!RtlpExecuteHandlerForException 06 ntdll!RtlDispatchException 07 ntdll!RtlRaiseException 08 KERNELBASE!RaiseException 09 VCRUNTIME140!_CxxThrowException 0a msvcp140!std::_Xout_of_range 0b tbb_expt!std::vector<int,std::allocator<int> >::_Xrange 0c tbb_expt!std::vector<int,std::allocator<int> >::at 0d tbb_expt!parallelFor::__l5::<lambda_66c7355d0edda6973d22642add3a91c2>::operator() 0e tbb_expt!std::_For_each_ivdep 0f tbb_expt!std::_Static_partitioned_for_each2<int *,__int64,<lambda_66c7355d0edda6973d22642add3a91c2> >::_Process_chunk 10 tbb_expt!std::_Run_available_chunked_work<std::_Static_partitioned_for_each2<int *,__int64,<lambda_66c7355d0edda6973d22642add3a91c2> > > 11 tbb_expt!std::_Static_partitioned_for_each2<int *,__int64,<lambda_66c7355d0edda6973d22642add3a91c2> >::_Threadpool_callback 12 ntdll!TppWorkpExecuteCallback 13 ntdll!TppWorkerThread 14 kernel32!BaseThreadInitThunk 15 ntdll!RtlUserThreadStart
we can safely say that
std::vector<int>::at() threw an exception of for out of range:
0a). This raised an error
_CxxThrowException at frame
09 and eventually lead to it trying to find exception handler to be executed:
FindHandler<__FrameHandler3> at frame
02, which we did not register in first place: thus it called
The code is to this effect:
Now the funny thing is: even if you change the execution policy to
std::execution::par_unseq, it will still crash the application. The rational behind this decision is to keep behavior consistent for API whether you are running parallel or not..
That’s it for now..