Skip to content

fix(read_env): only advertise inline_completion for set_value_t#2112

Open
nebkat wants to merge 1 commit into
NVIDIA:mainfrom
nebkat:fix/read_env-attrs-set-value-only
Open

fix(read_env): only advertise inline_completion for set_value_t#2112
nebkat wants to merge 1 commit into
NVIDIA:mainfrom
nebkat:fix/read_env-attrs-set-value-only

Conversation

@nebkat

@nebkat nebkat commented Jun 9, 2026

Copy link
Copy Markdown

read_env's __attrs::query was a member template, so it returned inline_completion for every completion tag - even set_error_t and set_stopped_t, which read_env never sends. That made let_value mistakenly classify chains like

read_env(q) | let_value([](auto v) { return some_async_sender; })

as inline-completing. The check __never_sends || behavior == inline_completion passed for every tag because read_env claimed inline across the board.

__as_awaitable then picked the inline __sender_awaiter, which holds the operation state as a local in await_suspend and destroys it at the closing brace. For any inner sender that hadn't actually completed by then, this is a use-after-free.

Example: Godbolt


Drop the _SetTag template parameter and bind the query directly to set_value_t - the only tag read_env sends - matching what __just::__attrs already does. The other tags now fall through to __unknown, the inline check correctly fails, and the non-inline awaiter gets selected.

@copy-pr-bot

copy-pr-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@Cra3z

Cra3z commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

I think the more fundamental cause lies in a flaw of the current let algorithm: right now, the attributes of a let sender merely forward those of the predecessor sender. This means that as long as the predecessor sender is inline-completing, the let sender becomes inline-completing, without taking the completion behavior of the successor sender into account.
See #2098 (comment).

@nebkat

nebkat commented Jun 9, 2026

Copy link
Copy Markdown
Author

Right, I did think that was unusual!

I presume this is still the correct completion behavior for a sender which only completes with set_value? just() uses the _JustTag::__tag_t to template __attrs<_SetTag> so it only defines the set_value completion behavior.

@ericniebler

Copy link
Copy Markdown
Collaborator

right now, the attributes of a let sender merely forward those of the predecessor sender.

right, pr #2077 is intended to fix this, but the pr is not finished yet, and i've been unavoidably detained. #2077 exposed a problem with the attributes of continues_on that needs to be addressed first.

Comment thread include/stdexec/__detail/__read_env.hpp
@nebkat nebkat force-pushed the fix/read_env-attrs-set-value-only branch 2 times, most recently from a3791fd to 1e412f7 Compare June 17, 2026 19:39
Comment thread include/stdexec/__detail/__read_env.hpp Outdated
}

STDEXEC_ATTRIBUTE(nodiscard)
constexpr auto query(__get_completion_behavior_t<set_error_t>) const noexcept

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be constrained on whether the query expression is potentially throwing.

@nebkat nebkat force-pushed the fix/read_env-attrs-set-value-only branch from 1e412f7 to 4aa7567 Compare June 19, 2026 00:06
`read_env`'s `__attrs::query` was a member template, so it returned
`inline_completion` for every completion tag - even `set_stopped_t`,
which read_env never sends. That made `let_value` mistakenly classify
chains like

    read_env(q) | let_value([](auto v) { return some_async_sender; })

as inline-completing. The check `__never_sends || behavior ==
inline_completion` passed for every tag because read_env claimed inline
across the board.

`__as_awaitable` then picked the inline `__sender_awaiter`, which holds
the operation state as a local in `await_suspend` and destroys it at the
closing brace. For any inner sender that hadn't actually completed by
then, this is a use-after-free.

Bind the query to the tags read_env actually completes with: always
`set_value_t`, and `set_error_t(exception_ptr)` only when the query is
potentially throwing - both complete inline within `start()`, matching
the completion signatures.
@nebkat nebkat force-pushed the fix/read_env-attrs-set-value-only branch from 4aa7567 to 9a30194 Compare June 19, 2026 00:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants