Skip to content

Commit 15389ac

Browse files
committed
New issue from Eric Niebler: "Potential dangling reference returned from transform_sender"
1 parent 3622cdc commit 15389ac

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

xml/issue4368.xml

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4368" status="New">
5+
<title>Potential dangling reference returned from `transform_sender`</title>
6+
<section>
7+
<sref ref="[exec.domain.default]"/>
8+
</section>
9+
<submitter>Eric Niebler</submitter>
10+
<date>31 Aug 2025</date>
11+
<priority>99</priority>
12+
13+
<discussion>
14+
<p>
15+
The following has been reported by Trevor Gray to me:
16+
</p>
17+
<blockquote style="border-left: 3px solid #ccc;padding-left: 15px;">
18+
<p>
19+
There is a potential stack-use-after-scope in `execution::transform_sender`
20+
with `execution::default_domain::transform_sender`.
21+
<p/>
22+
I'll give an example of the problem using `starts_on` with the `default_domain`.
23+
<p/>
24+
`starts_on` defines a `transform_sender` so `execution::transform_sender` will expand to:
25+
</p>
26+
<blockquote><pre>
27+
return transform_sender(
28+
dom,
29+
dom.transform_sender(std::forward&lt;Sndr&gt;(sndr), env...),
30+
env...);
31+
</pre></blockquote>
32+
<p>
33+
where `dom` is the `default_domain` and `sndr` is `starts_on`.
34+
<p/>
35+
Execution flow:
36+
</p>
37+
<ul>
38+
<li><p><tt>dom.transform_sender(std::forward&lt;Sndr&gt;(sndr), env...)</tt> uses `default_domain`
39+
to invoke `start_on`'s `transform_sender`. The return type is `T` (where `T` is a `let_value` sender)</p></li>
40+
<li><p><tt>transform_sender(dom, declval&lt;T&gt;(), env...)</tt> is then run which uses `default_domain`
41+
to just return <tt>std::forward&lt;T&gt;(t)</tt>.</p></li>
42+
</ul>
43+
<p>
44+
This means the value returned from the entire expression is <tt>T&amp;&amp;</tt> which a reference
45+
to a temporary variable in the frame of `transform_sender` which is no longer valid after the return.
46+
</p>
47+
</blockquote>
48+
<p>
49+
In the reference implementation, this scenario does not create a dangling reference because
50+
its implementation of `default_domain::transform_sender` does not conform to the spec. By default,
51+
it returns an rvalue sender as a prvalue instead of an xvalue as the spec requires.
52+
<p/>
53+
The fix is for the spec to follow suit and return prvalues when an xvalue would otherwise be returned.
54+
</p>
55+
</discussion>
56+
57+
<resolution>
58+
<p>
59+
This wording is relative to <paper num="N5014"/>.
60+
</p>
61+
62+
<ol>
63+
64+
<li><p>Modify <sref ref="[exec.domain.default]"/> as indicated:</p>
65+
66+
<blockquote>
67+
<pre>
68+
template&lt;sender Sndr, <i>queryable</i>... Env&gt;
69+
requires (sizeof...(Env) &lt;= 1)
70+
constexpr sender decltype(auto) transform_sender(Sndr&amp;&amp; sndr, const Env&amp;... env)
71+
noexcept(<i>see below</i>);
72+
</pre>
73+
<blockquote>
74+
<p>
75+
-2- Let `e` be the expression
76+
</p>
77+
<blockquote><pre>
78+
tag_of_t&lt;Sndr&gt;().transform_sender(std::forward&lt;Sndr&gt;(sndr), env...)
79+
</pre></blockquote>
80+
<p>
81+
if that expression is well-formed; otherwise, <tt><ins>static_cast&lt;Sndr&gt;(</ins>std::forward&lt;Sndr&gt;(sndr)<ins>)</ins></tt>.
82+
<p/>
83+
-3- <i>Returns</i>: `e`.
84+
<p/>
85+
-4- <i>Remarks</i>: The exception specification is equivalent to `noexcept(e)`.
86+
</p>
87+
</blockquote>
88+
</blockquote>
89+
90+
</li>
91+
92+
</ol></resolution>
93+
94+
</issue>

0 commit comments

Comments
 (0)