英文:
C++ coroutine segfaults when passing value through promise type
问题
I have a coroutine that co_awaits
three times to pick up new iterators feed in by the caller using the feed()
function of the return type Parser
. The values are stored within promise type and delivered on Awaitable::resume()
to referenced iterators from within the coroutine body (sorry I'm new to couroutines and I bet there's a better way to do that, please feel free to show me). In any case, this code segfaults:
#include <cstdio>
#include <coroutine>
#include <string_view>
struct Promise;
struct Parser : public std::coroutine_handle<Promise> {
using promise_type = ::Promise;
auto feed(std::convertible_to<std::string_view> auto&& view);
~Parser() {
destroy();
}
};
struct Awaitable {
Promise* promise;
std::string_view::iterator& start_;
std::string_view::iterator& end_;
Awaitable(std::string_view::iterator& start, std::string_view::iterator& end)
: start_{ start }
, end_{ end }
{ }
auto await_ready() -> bool { printf("await_ready!\n"); return true; }
auto await_suspend(std::coroutine_handle<Promise> handle) {
promise = &handle.promise();
printf("await_resume!\n");
}
auto await_resume() -> void;
};
struct Promise {
std::pair<std::string_view::iterator, std::string_view::iterator> iterpair;
auto get_return_object() -> Parser { return {Parser::from_promise(*this)}; };
auto initial_suspend() noexcept -> std::suspend_never { return {}; }
auto final_suspend() noexcept -> std::suspend_always { return {}; }
auto await_transform(std::pair<std::string_view::iterator, std::string_view::iterator> iterpair) -> Awaitable { return {iterpair.first, iterpair.second}; }
auto return_void() { printf("return void!\n"); }
// auto return_value() { printf("return void!\n"); }
auto unhandled_exception() {}
};
auto Awaitable::await_resume() -> void {
printf("await_resume!\n");
start_ = promise->iterpair.first;
end_ = promise->iterpair.second;
}
auto Parser::feed(std::convertible_to<std::string_view> auto&& view) {
auto my_view = std::string_view{ view };
promise().iterpair = { my_view.begin(), my_view.end() };
}
auto coro() -> Parser {
std::string_view::iterator start, end;
// feed1
co_await std::pair<std::string_view::iterator, std::string_view::iterator>{ start, end };
// feed2
co_await std::pair<std::string_view::iterator, std::string_view::iterator>{ start, end };
// feed3
co_await std::pair<std::string_view::iterator, std::string_view::iterator>{ start, end };
co_return;
}
int main() {
std::string_view part1 = "Hello sir!";
std::string_view part2 = "How is the world doing?";
std::string_view part3 = "Blazingly good sir!";
Parser myparser = coro();
myparser.feed(part1);
myparser.feed(part2);
myparser.feed(part3);
}
And I can't point my finger why it does so. Any hints?
英文:
I have a coroutine that co_awaits
three times to pick up new iterators feed in by the caller using the feed()
function of the return type Parser
. The values are stored within promise type and delivered on Awaitable::resume()
to referenced iterators from within the coroutine body (sorry I'm new to couroutines and I bet there's a better way to do that, please feel free to show me). In any case, this code segfaults:
#include <cstdio>
#include <coroutine>
#include <string_view>
struct Promise;
struct Parser : public std::coroutine_handle<Promise> {
using promise_type = ::Promise;
auto feed(std::convertible_to<std::string_view> auto&& view);
~Parser() {
destroy();
}
};
struct Awaitable {
Promise* promise;
std::string_view::iterator& start_;
std::string_view::iterator& end_;
Awaitable(std::string_view::iterator& start, std::string_view::iterator& end)
: start_{ start }
, end_{ end }
{ }
auto await_ready() -> bool { printf("await_ready!\n"); return true; }
auto await_suspend(std::coroutine_handle<Promise> handle) {
promise = &handle.promise();
printf("await_resume!\n");
}
auto await_resume() -> void;
};
struct Promise {
std::pair<std::string_view::iterator, std::string_view::iterator> iterpair;
auto get_return_object() -> Parser { return {Parser::from_promise(*this)}; };
auto initial_suspend() noexcept -> std::suspend_never { return {}; }
auto final_suspend() noexcept -> std::suspend_always { return {}; }
auto await_transform(std::pair<std::string_view::iterator, std::string_view::iterator> iterpair) -> Awaitable { return {iterpair.first, iterpair.second}; }
auto return_void() { printf("return void!\n"); }
// auto return_value() { printf("return void!\n"); }
auto unhandled_exception() {}
};
auto Awaitable::await_resume() -> void {
printf("await_resume!\n");
start_ = promise->iterpair.first;
end_ = promise->iterpair.second;
}
auto Parser::feed(std::convertible_to<std::string_view> auto&& view) {
auto my_view = std::string_view{ view };
promise().iterpair = { my_view.begin(), my_view.end() };
}
auto coro() -> Parser {
std::string_view::iterator start, end;
// feed1
co_await std::pair<std::string_view::iterator, std::string_view::iterator>{ start, end };
// feed2
co_await std::pair<std::string_view::iterator, std::string_view::iterator>{ start, end };
// feed3
co_await std::pair<std::string_view::iterator, std::string_view::iterator>{ start, end };
co_return;
}
int main() {
std::string_view part1 = "Hello sir!";
std::string_view part2 = "How is the world doing?";
std::string_view part3 = "Blazingly good sir!";
Parser myparser = coro();
myparser.feed(part1);
myparser.feed(part2);
myparser.feed(part3);
}
And I can't point my finger why it does so. Any hints?
答案1
得分: 2
await_ready()
返回 true
意味着协程不会被挂起,因此不会调用 await_suspend
。
由于未调用 await_suspend
,promise
未初始化。然后,在执行 await_resume()
时,start_ = promise->iterpair.first;
使用悬空指针 promise
,导致崩溃。
英文:
await_ready()
returning true
means the coroutine will not be suspended, and thus await_suspend
will not be invoked.
Since await_suspend
is not called, promise
is not initialized. Then, when await_resume()
is executed, start_ = promise->iterpair.first;
uses the dangling pointer promise
, which causes the crash.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论