【发布时间】:2020-06-20 20:21:35
【问题描述】:
Folly 有一个可用于 C++20 风格协同程序的库。
在它声称的自述文件中:
重要提示:您需要非常小心临时 lambda 对象的生命周期。调用 lambda 协程会返回一个 folly::coro::Task 捕获对 lambda 的引用,因此如果返回的 Task 没有立即 co_awaited,那么当临时 lambda 超出范围时,该任务将留下一个悬空引用。
我尝试为他们提供的示例制作 MCVE,但对结果感到困惑。 为以下所有示例假设以下样板:
#include <folly/experimental/coro/Task.h>
#include <folly/experimental/coro/BlockingWait.h>
#include <folly/futures/Future.h>
using namespace folly;
using namespace folly::coro;
int main() {
fmt::print("Result: {}\n", blockingWait(foo()));
}
我用地址清理器编译了以下内容,看看是否会有任何悬空引用。
编辑:澄清问题
问题:为什么第二个示例没有触发 ASAN 警告?
根据cppreference:
当协程到达 co_return 语句时,它会执行以下操作:
...
- 或为 co_return expr 调用 promise.return_value(expr),其中 expr 具有非 void 类型
- 以与创建时相反的顺序销毁所有具有自动存储持续时间的变量。
- 调用 promise.final_suspend() 和 co_await 是结果。
因此,也许在返回结果之前临时 lambda 的状态实际上并没有被销毁,因为foo 本身就是一个协程?
ASAN 错误:我假设等待协程时“i”不存在
auto foo() -> Task<int> {
auto task = [i=1]() -> folly::coro::Task<int> {
co_return i;
}(); // lambda is destroyed after this semicolon
return task;
}
没有错误——为什么?
auto foo() -> Task<int> {
auto task = [i=1]() -> folly::coro::Task<int> {
co_return i;
}();
co_return co_await std::move(task);
}
ASAN 错误:与第一个示例相同的问题?
auto foo() -> folly::SemiFuture<int> {
auto task = [i=1]() -> folly::coro::Task<int> {
co_return i;
}();
return std::move(task).semi();
}
NO ERROR ...而且为了更好地衡量,只需返回一个常量(未捕获 lambda 状态)就可以正常工作。与第一个示例比较:
auto foo() -> Task<int> {
auto task = []() -> folly::coro::Task<int> {
co_return 1;
}();
return task;
}
【问题讨论】:
-
auto task = [i=1]() -> folly::coro::Task<int> { co_await something; co_return i; }将触发 UAF。 -
我不介意投反对票作为反馈,但我不确定为什么投反对票。问题太模棱两可?没有足够的研究?
-
C++ 社区...
标签: c++ c++20 folly c++-coroutine