Skip to content

Commit f67e55a

Browse files
authored
Don't destroy the IAsyncInfo from inside Completed handler (#671)
1 parent 4fa0e40 commit f67e55a

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

strings/base_coroutine_foundation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ namespace winrt::impl
140140

141141
void await_suspend(std::experimental::coroutine_handle<> handle)
142142
{
143+
auto extend_lifetime = async;
143144
async.Completed([this, handler = disconnect_aware_handler{ handle }](auto&&, auto operation_status) mutable
144145
{
145146
status = operation_status;

test/test/async_completed.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include "pch.h"
2+
3+
using namespace winrt;
4+
using namespace Windows::Foundation;
5+
6+
namespace
7+
{
8+
//
9+
// Checks that awaiting an already-completed async operation
10+
// does not destroy the operation from within the Completed handler.
11+
// The Completed handler may run synchronously, and destroying the
12+
// operation from within the Completed handler pulls the rug out
13+
// from under the operation!
14+
//
15+
struct already_completed : implements<already_completed, IAsyncAction, IAsyncInfo>
16+
{
17+
void Completed(AsyncActionCompletedHandler const& complete)
18+
{
19+
auto self = get_weak();
20+
complete(*this, AsyncStatus::Completed);
21+
REQUIRE(self.get() != nullptr);
22+
}
23+
24+
auto Completed() const noexcept
25+
{
26+
return nullptr;
27+
}
28+
29+
uint32_t Id() const noexcept
30+
{
31+
return 1;
32+
}
33+
34+
AsyncStatus Status() const noexcept
35+
{
36+
return AsyncStatus::Completed;
37+
}
38+
39+
hresult ErrorCode() const noexcept
40+
{
41+
return 0;
42+
}
43+
44+
void GetResults() const noexcept
45+
{
46+
}
47+
48+
void Cancel() const noexcept
49+
{
50+
}
51+
52+
void Close() const noexcept
53+
{
54+
}
55+
};
56+
57+
IAsyncAction TestCompleted()
58+
{
59+
co_await make<already_completed>();
60+
}
61+
}
62+
63+
TEST_CASE("async_completed")
64+
{
65+
TestCompleted().get();
66+
}

test/test/test.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@
293293
<ClCompile Include="async_auto_cancel.cpp" />
294294
<ClCompile Include="async_cancel_callback.cpp" />
295295
<ClCompile Include="async_check_cancel.cpp" />
296+
<ClCompile Include="async_completed.cpp" />
296297
<ClCompile Include="box_guid.cpp" />
297298
<ClCompile Include="capture.cpp" />
298299
<ClCompile Include="coro_foundation.cpp">

0 commit comments

Comments
 (0)