Skip to content

potential dangling reference returned from transform_sender #343

Open

Description

@ericniebler

quoting from an email i received from Trevor Gray:

There is a potential stack-use-after-scope in execution::transform_sender with execution::default_domain::transform_sender.

I'll give an example of the problem using starts_on with the default_domain.

starts_on defines a transform_sender so execution::transform_sender will expand to:

return transform_sender(
    dom,
    dom.transform_sender(std::forward<Sndr>(sndr), env...),
    env...);

dom is the default_domain
sndr is starts_on

Execution flow:

  • dom.transform_sender(std::forward<Sndr>(sndr), env...) uses default_domain to invoke start_on's transform_sender. The return type is T (where T is a let_value sender)
  • transform_sender(dom, declval<T>(), env...) is then run which uses default_domain to just return std::forward<T>(t).

This means the value returned from the entire expression is T&& which a reference to a temporary variable in the frame of transform_sender which is no longer valid after the return

Discussion

in the reference implementation, this scenario does not create a dangling reference because its implementation of default_domain::transform_sender does not conform to the spec. by default, it returns an rvalue sender as a prvalue instead of an xvalue as the spec requires.

the fix is for the spec to follow suit and return prvalues when an xvalue would otherwise be returned.

Proposed resolution

Change [exec.domain.default]/p2 should be changed from:

  1. Let e be the expression tag_of_t<Sndr>().transform_sender(std::forward<Sndr>(sndr), env...)
    if that expression is well-formed; otherwise, std​::​forward<Sndr>(sndr).

to:

  1. Let e be the expression tag_of_t<Sndr>().transform_sender(std::forward<Sndr>(sndr), env...)
    if that expression is well-formed; otherwise, static_cast<Sndr>(std​::​forward<Sndr>(sndr)).

Activity

  1. lewissbaker commented on Nov 25, 2025

    @lewissbaker
    Collaborator

    This has been filed as https://cplusplus.github.io/LWG/issue4368

    Note that I also filed the same issue with lwgchair on 2025-08-26, but suggested a different resolution.

    Let /final-sndr/ be the expression /transformed-sndr/ if /transformed-sndr/ and sndr have the same type ignoring cv-qualifiers; otherwise it is the expression auto(transform_sender(dom, transformed-sndr, env...)).

    I think the static_cast<Sndr>(std::forward<Sndr>(sndr)) approach also solves the xvalue issue but would avoid making copies when passed an lvalue so may be the better approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions