<div class="__aliyun_email_body_block"><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">Hi Adrian,</span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;"><br ></span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">I met this problem before. I agree that this behavior would make symmetric transfer much harder.</span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;"><br ></span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">From my point of view, this is an undefined behavior. From 17.12.4.6 of N4878, we can find:</span></div><div style="clear:both;">```</div><div style="clear:both;"><p style="margin:.0px;font-variant-caps:normal;font-stretch:normal;line-height:normal;"><span style="font-style:normal;font-weight:normal;font-family:Helvetica;font-size:16.0px;">void destroy() const;</span></p><p style="margin:.0px;font-variant-caps:normal;font-stretch:normal;line-height:normal;"><span style="font-size:16.0px;"><span style="font-style:normal;font-variant-caps:normal;font-weight:normal;font-stretch:normal;font-size:16.0px;line-height:normal;font-family:Helvetica;">4 </span><span style="font-style:normal;font-weight:normal;font-size:16.0px;font-family:Helvetica;">Preconditions: *this refers to a suspended coroutine.</span></span></p><p style="margin:.0px;font-variant-caps:normal;font-stretch:normal;line-height:normal;"><span style="font-style:normal;font-variant-caps:normal;font-weight:normal;font-stretch:normal;line-height:normal;font-family:Helvetica;font-size:16.0px;">5 </span><span style="font-style:normal;font-weight:normal;font-family:Helvetica;font-size:16.0px;">Effects: Destroys the coroutine</span></p></div><div style="clear:both;">```</div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;"><br ></span></div><div style="clear:both;">To my mind, the coroutine **isn't suspended** in the await_suspend. So it is an undefined behavior if we call `coroutine_handle::destroy()` in await_suspend.</div><div style="clear:both;"><br ></div><div style="clear:both;">But I strongly agree with you it is really suffering that if we want symmetric transfer and we can't destroy the coroutine in final await_suspend directly.</div><div style="clear:both;"><br ></div><div style="clear:both;">I would look into the details and try to fix it.</div><div style="clear:both;"><br ></div><div style="clear:both;">Thanks,</div><div style="clear:both;">Chuanqi</div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;"><br ></span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;"><br ></span></div><blockquote style="margin-right:0;margin-top:0;margin-bottom:0;"><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">------------------------------------------------------------------</span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">From:Adrian Vogelsgesang via cfe-dev <cfe-dev@lists.llvm.org></span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">Send Time:2021年2月4日(星期四) 04:21</span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">To:cfe-dev@lists.llvm.org <cfe-dev@lists.llvm.org></span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">Subject:[cfe-dev] Miscompilation: heap-use-after-free in C++ coroutines</span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;"><br ></span></div><style >!-- @font-face{font-family:Cambria Math;panose-1:2 4 5 3 5 4 6 3 2 4;}{font-family:Calibri;panose-1:2 15 5 2 2 2 4 3 2 4;}p.MsoNormal, li.MsoNormal, div.MsoNormal{margin:.0cm;font-size:11.0pt;font-family:Calibri,sans-serif;mso-fareast-language:EN-US;}a:link, span.MsoHyperlink{mso-style-priority:99;color:#0563c1;text-decoration:underline;}span.apple-converted-space{mso-style-name:apple-converted-space;}.MsoChpDefault{mso-style-type:export-only;font-size:10.0pt;font-family:Calibri,sans-serif;mso-fareast-language:EN-US;}@page WordSection1{size:612.0pt 792.0pt;margin:72.0pt 72.0pt 72.0pt 72.0pt;}div.WordSection1{page:WordSection1;}--></style><div class="WordSection1"><p class="MsoNormal"><span class=" __aliyun_node_has_color" style="color:black;">Dear Clang community,<br ><br >
I think I stumbled across a front-end bug in clang’s coroutine implementation.<br ><br >
Having an awaitable with<br ><br >
```<br ></span><span class=" __aliyun_node_has_color" style="color:black;">template<typename PROMISE> std::experimental::coroutine_handle<> await_suspend(std::experimental::coroutine_handle<PROMISE> coro) noexcept {</span></p><p class="MsoNormal" style="caret-color:#000000;font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;"><span class=" __aliyun_node_has_color" style="color:black;"> coro.destroy();</span></p><p class="MsoNormal" style="caret-color:#000000;font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;"><span class=" __aliyun_node_has_color" style="color:black;"> return std::experimental::noop_coroutine();</span></p><p class="MsoNormal" style="caret-color:#000000;font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;"><span class=" __aliyun_node_has_color" style="color:black;">}<br ></span><span class=" __aliyun_node_has_color" style="color:black;">```<br ><br >
destroys the function’s own coroutine frame. This is valid, as long as no-one afterwards resumes the coroutine anymore. However, address-sanitizer reports a heap-use-after-free error (see
<a href="https://godbolt.org/z/eq6eoc" target="_blank">https://godbolt.org/z/eq6eoc</a> )<br ><br >
Afaict, this is because clang stores the return value of `await_suspend` in the coroutine frame. Instead, clang should probably store this return value on the stack. Storing on the stack should be valid, as it is guaranteed that this return value will never
live across a suspension point.<br ><br >
You can find a minimal repro in <a href="https://godbolt.org/z/eq6eoc" target="_blank">https://godbolt.org/z/eq6eoc</a> and a more complex end-to-end version in <a href="https://godbolt.org/z/8Yadv1" target="_blank">https://godbolt.org/z/8Yadv1</a> .
See </span><span class=" __aliyun_node_has_color" style="color:black;"><a href="https://stackoverflow.com/questions/65991264/c-coroutines-is-it-valid-to-call-handle-destroy-from-the-final-suspend-poin" target="_blank">https://stackoverflow.com/questions/65991264/c-coroutines-is-it-valid-to-call-handle-destroy-from-the-final-suspend-poin</a></span><span class=" __aliyun_node_has_color" style="color:black;"> </span><span class=" __aliyun_node_has_color" style="color:black;">(in
particular the comments to David Haim’s reply) for more context.<br ><br >
Cheers,<br >
Adrian</span></p><p class="MsoNormal"> </p></div></blockquote><div ><br ></div></div>