microsoft / wil

Windows Implementation Library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

wil::com_task does not propagate thread-local restricted error information across thread boundaries

dmachaj opened this issue · comments

I have a crash that I'm debugging and it has been difficult to debug because the UI thread doesn't have the original stowed exception information. The first RoOriginateError call on the UI thread is in the winrt::terminate handler when we are already going down a fatal code path. After trying lots of different approaches I finally thought to check for stowed exceptions on every thread in the process and sure enough one of the background threads has the "real" original exception.

The program in question is roughly as follows:

wil::com_task<Foo> DoThingAsync()
{
  co_await winrt::resume_background();
  THROW_HR(E_FAIL); // oopsies
  co_return foo;
}

winrt::fire_and_forget UpdateUI()
{
  try
  {
    auto result = co_await DoThingAsync();
  }
  catch (winrt::hresult_error&)
  { /* handle */ }
}

My true bug is that we catch winrt::hresult_error but not wil::ResultException so the catch block doesn't catch and the exception hits the winrt::fire_and_forget noexcept boundary. That crashes the process. Now that I understand the problem it is easy enough to fix.

I am filing this issue because it was overly difficult to figure this out based on a crash dump. I think the situation could be improved if wil::com_task were to call GetRestrictedErrorInfo on the background thread and if it is non-null propagate it to the UI thread with a call to SetRestrictedErrorInfo. The auto-originate would have then seen the original and let it remain active. Failure analysis would have also pointed me far more directly at the true problem.