Skip to content

Commit ce822db

Browse files
authored
Merge pull request #2014 from ericniebler/fix-lifetime-issue-in-stdexec-task
put the receiver at a stable address so the env pulled from it stays valid
2 parents de79423 + cb3ca1e commit ce822db

1 file changed

Lines changed: 23 additions & 21 deletions

File tree

include/stdexec/__detail/__task.hpp

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -472,12 +472,10 @@ namespace STDEXEC
472472
return __parent_.unhandled_stopped();
473473
}
474474

475-
// STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
476475
__own_env_t<_ParentPromise> __own_env_;
477-
// STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
478-
_Env __env_;
479-
__std::coroutine_handle<> __continuation_;
480-
_ParentPromise& __parent_;
476+
_Env __env_;
477+
__std::coroutine_handle<> __continuation_;
478+
_ParentPromise& __parent_;
481479
};
482480

483481
struct __attrs
@@ -507,30 +505,37 @@ namespace STDEXEC
507505
__std::coroutine_handle<promise_type> __coro_;
508506
};
509507

508+
template <class _Rcvr>
509+
struct __rcvr_box
510+
{
511+
_Rcvr __rcvr_;
512+
};
513+
510514
////////////////////////////////////////////////////////////////////////////////////////
511515
// task<T,E>::__opstate
512516
template <class _Ty, class _Env>
513517
template <class _Rcvr>
514518
struct STDEXEC_ATTRIBUTE(empty_bases) task<_Ty, _Env>::__opstate final
515-
: __opstate_base
519+
: __rcvr_box<_Rcvr> // holds the receiver so that we can pass __opstate_base a reference to it
520+
, __opstate_base
516521
, __stop_callback_box_t<_Rcvr>
517522
{
518523
public:
519524
using operation_state_concept = operation_state_tag;
520525

521526
explicit __opstate(task&& __task, _Rcvr&& __rcvr) noexcept
522-
: __opstate_base(static_cast<task&&>(__task), __rcvr)
523-
, __own_env_(__mk_own_env(__rcvr))
524-
, __env_(__mk_env(__rcvr, __own_env_))
525-
, __rcvr_(static_cast<_Rcvr&&>(__rcvr))
527+
: __rcvr_box<_Rcvr>{static_cast<_Rcvr&&>(__rcvr)}
528+
, __opstate_base(static_cast<task&&>(__task), this->__rcvr_)
529+
, __own_env_(__mk_own_env(this->__rcvr_))
530+
, __env_(__mk_env(this->__rcvr_, __own_env_))
526531
{}
527532

528533
void start() & noexcept
529534
{
530535
STDEXEC_TRY
531536
{
532537
// Register a stop callback if needed
533-
this->__register_callback(__rcvr_, this->__handle().promise().__stop_);
538+
this->__register_callback(this->__rcvr_, this->__handle().promise().__stop_);
534539
this->__handle().resume();
535540
}
536541
STDEXEC_CATCH_ALL
@@ -542,7 +547,7 @@ namespace STDEXEC
542547
else if constexpr (__mapply<__mcontains<set_error_t(std::exception_ptr)>,
543548
error_types>::value)
544549
{
545-
STDEXEC::set_error(static_cast<_Rcvr&&>(__rcvr_), std::current_exception());
550+
STDEXEC::set_error(static_cast<_Rcvr&&>(this->__rcvr_), std::current_exception());
546551
}
547552
else
548553
{
@@ -565,19 +570,19 @@ namespace STDEXEC
565570
// Move the errors out of the promise before destroying the coroutine.
566571
auto __errors = std::move(this->__errors_);
567572
__sink(static_cast<task&&>(this->__task_));
568-
__visit(STDEXEC::set_error, std::move(__errors), static_cast<_Rcvr&&>(__rcvr_));
573+
__visit(STDEXEC::set_error, std::move(__errors), static_cast<_Rcvr&&>(this->__rcvr_));
569574
}
570575
else if constexpr (__same_as<_Ty, void>)
571576
{
572577
__sink(static_cast<task&&>(this->__task_));
573-
STDEXEC::set_value(static_cast<_Rcvr&&>(__rcvr_));
578+
STDEXEC::set_value(static_cast<_Rcvr&&>(this->__rcvr_));
574579
}
575580
else
576581
{
577582
// Move the result out of the promise before destroying the coroutine.
578583
_Ty __result = static_cast<_Ty&&>(*this->__handle().promise().__result_);
579584
__sink(static_cast<task&&>(this->__task_));
580-
STDEXEC::set_value(static_cast<_Rcvr&&>(__rcvr_), static_cast<_Ty&&>(__result));
585+
STDEXEC::set_value(static_cast<_Rcvr&&>(this->__rcvr_), static_cast<_Ty&&>(__result));
581586
}
582587
}
583588
STDEXEC_CATCH_ALL
@@ -586,7 +591,7 @@ namespace STDEXEC
586591
|| !__nothrow_move_constructible<__error_variant_t>)
587592
{
588593
__sink(static_cast<task&&>(this->__task_));
589-
STDEXEC::set_error(static_cast<_Rcvr&&>(__rcvr_), std::current_exception());
594+
STDEXEC::set_error(static_cast<_Rcvr&&>(this->__rcvr_), std::current_exception());
590595
}
591596
}
592597
return std::noop_coroutine();
@@ -596,15 +601,12 @@ namespace STDEXEC
596601
{
597602
this->__reset_callback();
598603
__sink(static_cast<task&&>(this->__task_));
599-
STDEXEC::set_stopped(static_cast<_Rcvr&&>(__rcvr_));
604+
STDEXEC::set_stopped(static_cast<_Rcvr&&>(this->__rcvr_));
600605
return std::noop_coroutine();
601606
}
602607

603-
// STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
604608
__own_env_t<_Rcvr> __own_env_;
605-
// STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
606-
_Env __env_;
607-
_Rcvr __rcvr_;
609+
_Env __env_;
608610
};
609611

610612
////////////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)