{"id":108693,"date":"2023-09-01T07:00:00","date_gmt":"2023-09-01T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108693"},"modified":"2023-08-31T20:15:39","modified_gmt":"2023-09-01T03:15:39","slug":"20230901-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230901-00\/?p=108693","title":{"rendered":"How do I find out more about the fail-fast exception that occurs when an exception in a PPL task goes unobserved?"},"content":{"rendered":"<p>If an exception happens during the execution of a Parallel Patterns Library (PPL) <code>task<\/code>, the exception is stowed in the task, with the expectation that you will inspect the task to see whether or not it succeeded. But if you destruct the task without ever checking, then PPL fails fast with an unhandled exception, analogous with leaving an exception unhandled in non-task code.<\/p>\n<pre>__declspec(noinline)\r\n~_ExceptionHolder()\r\n{\r\n    if (_M_exceptionObserved == 0)\r\n    {\r\n        \/\/ If you are trapped here, it means an exception thrown in task chain\r\n        \/\/ didn't get handled. Please add task-based continuation to handle all\r\n        \/\/ exceptions coming from tasks. this-&gt;_M_stackTrace keeps the creation\r\n        \/\/ callstack of the task generates this exception.\r\n        _REPORT_PPLTASK_UNOBSERVED_EXCEPTION();\r\n    }\r\n}\r\n<\/pre>\n<p>If your code is compiled in debug mode, PPL captures a stack trace at the point the first task in the task chain is created. If your code is compiled in release mode, PPL captures only the first stack in the trace.<\/p>\n<p>When you get to the <code>_REPORT_<wbr \/>PPLTASK_<wbr \/>UNOBSERVED_<wbr \/>EXCEPTION();<\/code>, you can look at the <code>this<\/code> pointer&#8217;s <code>_M_stackTrace<\/code> to see where the task chain started.<\/p>\n<p>In debug mode:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; font-size: 80%;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>this<\/td>\n<td>0x000001c9976ec0f0<\/td>\n<td>Concurrency::details::_ExceptionHolder *<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003_M_exceptionObserved<\/td>\n<td>0<\/td>\n<td>std::atomic&lt;long&gt;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003_M_stdException<\/td>\n<td>{&#8230;}<\/td>\n<td>std::exception_ptr<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003_M_stackTrace<\/td>\n<td>{[capacity]=9<\/td>\n<td>Concurrency::details::_TaskCreationCallstack<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003\u2003[capacity]<\/td>\n<td>9<\/td>\n<td>void*<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003\u2003[allocator]<\/td>\n<td>allocator<\/td>\n<td>std::_<a title=\"Inside STL: The pair and the compressed pair\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230801-00\/?p=108509\">Compressed_pair<\/a>&lt;std::allocator&lt;voi\u2026<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003\u2003[0]<\/td>\n<td>0x00007ff7d1b96792 {contoso.exe!StartSo\u2026<\/td>\n<td>void*<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003\u2003[1]<\/td>\n<td>0x00007ff7d1b96836 {contoso.exe!StudyS\u2026<\/td>\n<td>void*<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003\u2003\u22ee<\/td>\n<td>\u22ee<\/td>\n<td>\u22ee<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<pre style=\"white-space: pre-wrap;\">(8930.74bc): C++ EH exception - code e06d7363 (first chance)\r\nWin32!Concurrency::details::_ExceptionHolder::~_ExceptionHolder+0x3e:\r\n00007ff7`d1b93c5e cc              int     3\r\n0:004&gt; ?? this\r\nstruct Concurrency::details::_ExceptionHolder * 0x000001c9`976ec0f0\r\n   +0x000 _M_exceptionObserved : std::atomic&lt;long&gt;\r\n   +0x008 _M_stdException  : std::exception_ptr\r\n   +0x018 _M_stackTrace    : Concurrency::details::_TaskCreationCallstack\r\n0:004&gt; ?? this-&gt;_M_stackTrace\r\nclass Concurrency::details::_TaskCreationCallstack\r\n   +0x000 _M_SingleFrame   : 0x00007ff7`d1b96792 Void\r\n   +0x008 _M_frames        : std::vector&lt;void *,std::allocator&lt;void *&gt; &gt;\r\n0:004&gt; ?? this-&gt;_M_stackTrace._M_frames\r\nclass std::vector&lt;void *,std::allocator&lt;void *&gt; &gt;\r\n   +0x000 _Mypair          : std::_Compressed_pair&lt;std::allocator&lt;void *&gt;,std::_Vector_val&lt;std::_Simple_types&lt;void *&gt; &gt;,1&gt;\r\n0:004&gt; ?? this-&gt;_M_stackTrace._M_frames._Mypair\r\nclass std::_Compressed_pair&lt;std::allocator&lt;void *&gt;,std::_Vector_val&lt;std::_Simple_types&lt;void *&gt; &gt;,1&gt;\r\n   +0x000 _Myval2          : std::_Vector_val&lt;std::_Simple_types&lt;void *&gt; &gt;\r\n0:004&gt; ?? this-&gt;_M_stackTrace._M_frames._Mypair._Myval2\r\nclass std::_Vector_val&lt;std::_Simple_types&lt;void *&gt; &gt;\r\n   +0x000 _Myproxy         : 0x00000257`42a08840 std::_Container_proxy\r\n   +0x008 _Myfirst         : 0x00000257`42a08000  -&gt; 0x00007ff7`d1b96792 Void\r\n   +0x010 _Mylast          : 0x00000257`42a08048  -&gt; 0xabababab`fdfdfdfd Void\r\n   +0x018 _Myend           : 0x00000257`42a08048  -&gt; 0xabababab`fdfdfdfd Void\r\n0:004&gt; dps 0x00000257`42a08000 0x00000257`42a08048\r\n00000257`42a08000  00007ff7`d1b96792 contoso!StartSomething+0x92 [something.cpp @ 372]\r\n00000257`42a08008  00007ff7`d1b96836 contoso!StudySomething+0x56 [something.cpp @ 377]\r\n...\r\n<\/pre>\n<p>Here we took advantage of what we learned earlier about <a title=\"Inside STL: The pair and the compressed pair\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230801-00\/?p=108509\"> compressed pairs<\/a> and <a title=\"Inside STL: The vector\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230802-00\/?p=108524\"> <code>std::<wbr \/>vector<\/code><\/a>.<\/p>\n<p>In release mode:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; font-size: 80%;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>this<\/td>\n<td>0x000001911e62aab0<\/td>\n<td>Concurrency::details::_ExceptionHolder *<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003_M_exceptionObserved<\/td>\n<td>0<\/td>\n<td>std::atomic&lt;long&gt;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003_M_stdException<\/td>\n<td>{&#8230;}<\/td>\n<td>std::exception_ptr<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003_M_stackTrace<\/td>\n<td>{[0]=0x00007ff61b9532f0 {contoso.exe!StartS\u2026<\/td>\n<td>Concurrency::details::_TaskCreationCallstack<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003\u2003[0]<\/td>\n<td>0x00007ff61b9532f0 {contoso.exe!StartSomet\u2026<\/td>\n<td>void*<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003\u2003[Raw View]<\/td>\n<td>{_M_SingleFrame=0x00007ff61b9532f0 {con\u2026<\/td>\n<td>Concurrency::details::_TaskCreationCallstack<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003\u2003\u2003_M_SingleFrame<\/td>\n<td>0x00007ff61b9532f0 {contoso.exe!StartSomet\u2026<\/td>\n<td>void*<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003\u2003\u2003_M_frames<\/td>\n<td>{ size=0 }<\/td>\n<td>std::vector&lt;void*&gt;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<pre style=\"white-space: pre-wrap;\">(ae88.8188): C++ EH exception - code e06d7363 (first chance)\r\ncontoso!Concurrency::details::_ExceptionHolder::~_ExceptionHolder+0x15:\r\n00007ff7`c4591be5 cc              int     3\r\n0:004&gt; dv\r\n           this = 0x00000191`1e62aab0\r\n0:004&gt; ?? this\r\nstruct Concurrency::details::_ExceptionHolder * 0x00000191`1e62aab0\r\n   +0x000 _M_exceptionObserved : std::atomic&lt;long&gt;\r\n   +0x008 _M_stdException  : std::exception_ptr\r\n   +0x018 _M_stackTrace    : Concurrency::details::_TaskCreationCallstack\r\n0:004&gt; ?? this-&gt;_M_stackTrace\r\nclass Concurrency::details::_TaskCreationCallstack\r\n   +0x000 _M_SingleFrame   : 0x00007ff6`1b9532f0  Void\r\n   +0x008 _M_frames        : std::vector&lt;void *,std::allocator&lt;void *&gt; &gt;\r\n\r\n0:004&gt; u 0x00007ff7`c45932f0 L1\r\ncontoso!StartSomething+0xe0: [something.cpp @ 377]\r\n00007ff7`c45932f0 90              lea     r9,[rbp-68h]\r\n<\/pre>\n<p>We can see in the debugger that the frames vector is empty:<\/p>\n<pre style=\"white-space: pre-wrap;\">0:004&gt; ?? this-&gt;_M_stackTrace._M_frames\r\nclass std::vector&lt;void *,std::allocator&lt;void *&gt; &gt;\r\n   +0x000 _Mypair          : std::_Compressed_pair&lt;std::allocator&lt;void *&gt;,std::_Vector_val&lt;std::_Simple_types&lt;void *&gt; &gt;,1&gt;\r\n0:004&gt; ?? this-&gt;_M_stackTrace._M_frames._Mypair\r\nclass std::_Compressed_pair&lt;std::allocator&lt;void *&gt;,std::_Vector_val&lt;std::_Simple_types&lt;void *&gt; &gt;,1&gt;\r\n   +0x000 _Myval2          : std::_Vector_val&lt;std::_Simple_types&lt;void *&gt; &gt;\r\n0:004&gt; ?? this-&gt;_M_stackTrace._M_frames._Mypair._Myval2\r\nclass std::_Vector_val&lt;std::_Simple_types&lt;void *&gt; &gt;\r\n   +0x000 _Myfirst         : (null)\r\n   +0x008 _Mylast          : (null)\r\n   +0x010 _Myend           : (null)\r\n<\/pre>\n<p>Older versions of the Parallel Patterns Library captured only the top frame of the stack in a member variable named <code>_M_disassemble\u00adMe<\/code>:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; font-size: 80%;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>this<\/td>\n<td>0x000001ed8a3b6f10<\/td>\n<td>Concurrency::details::_ExceptionHolder *<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003_M_exceptionObserved<\/td>\n<td>0<\/td>\n<td>volatile long<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003_M_stdException<\/td>\n<td>{&#8230;}<\/td>\n<td>std::exception_ptr<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2003_M_disassembleMe<\/td>\n<td>0x00007ff61b9532f0 {contoso.exe!StartSomething(void), Line 377} }<\/td>\n<td>void*<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If C++\/CX support is enabled, then there is also a member called <code>_M_winrt\u00adException<\/code>. Windows Runtime exceptions are stored in the <code>_M_winrt\u00adException<\/code> member; all others are stored in the <code>_M_std\u00adException<\/code>.<\/p>\n<p>You can then use <a title=\"Inside the Microsoft STL: The std::exception_ptr\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200820-00\/?p=104097\"> previously-discussed techniques<\/a> to extract the thrown exception and learn more about what went wrong.<\/p>\n<pre>0:004&gt; ?? this-&gt;_M_stdException\r\nclass std::exception_ptr\r\n   +0x000 _Data1           : 0x00000257`42a24880 Void\r\n   +0x008 _Data2           : 0x00000257`42a24870 Void\r\n0:004&gt; .exr 0x00000257`42a24880\r\nExceptionAddress: 0000000000000000\r\n   ExceptionCode: e06d7363 (C++ EH exception)\r\n  ExceptionFlags: 00000001\r\nNumberParameters: 4\r\n   Parameter[0]: 0000000019930520\r\n   Parameter[1]: 0000025742a24920\r\n   Parameter[2]: 00007ff7bd414518\r\n   Parameter[3]: 00007ff7bd310000\r\n  pExceptionObject: 0000025742a24920\r\n  _s_ThrowInfo    : 00007ff7bd414518\r\n0:004&gt; dps 0000025742a24920 L2\r\n00000257`42a24920  00007ff7`bd4066b8 contoso!std::bad_alloc::`vftable'\r\n00000257`42a24928  00007ff7`bd4066d0 contoso!`string'\r\n<\/pre>\n<p><b>Bonus reading<\/b>: <a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/improved-exception-reporting-for-c-windows-store-apps-in-visual-studio-2013\/\"> Improved exception reporting for C++ Windows Store Apps in Visual Studio 2013<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Digging into the internals.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-108693","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Digging into the internals.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108693","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=108693"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108693\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=108693"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108693"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108693"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}