You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何构造C++ future引用局部变量导致崩溃的稳定复现程序

C++ future 悬挂引用问题稳定复现方法

现有代码未崩溃的原因

你当前的测试程序未触发崩溃是未定义行为的典型表现,核心原因有两点:

  • doThing返回后,local_state所在的栈内存暂时没有被其他函数调用覆盖,残留值仍然是之前的有效值
  • 部分版本Boost的future::then默认会inline执行延续任务,如果前序异步任务在doThing返回前就进入完成状态,延续任务甚至可能在local_state生命周期结束前就执行完毕

稳定复现的修改方案

只需要做三处调整就能稳定暴露问题:

  1. 把内置类型的local_state替换为带析构逻辑的自定义类型,析构时主动覆写内存,避免残留有效值
  2. 在doThing返回后、调用future.get()前,插入栈污染逻辑,覆盖原local_state所在的栈空间
  3. 延长前序异步任务的等待时间,确保doThing先完成返回、栈帧完全销毁后,延续任务才开始执行

修改后的测试代码如下:

#include <iostream>
#include <cstring>
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
#define BOOST_THREAD_PROVIDES_FUTURE
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include <boost/thread/future.hpp>

// 自定义类型,析构时主动覆写内存
struct State {
    int val = 0;
    ~State() {
        // 覆写为乱码值
        val = 0xdeadbeef;
    }
};

void computeResult(State& s) {
    boost::this_thread::sleep_for(boost::chrono::seconds(2));
    std::cout << "computeResult 中读取值: " << s.val << std::endl;
    s.val += 1;
}

// 栈污染函数,占用同一块栈空间覆写内存
void pollute_stack() {
    char buf[1024];
    std::memset(buf, 0xcc, sizeof(buf));
    // 加局部变量避免编译器优化掉该函数
    int volatile tmp = buf[0];
    (void)tmp;
}

boost::future<int> doThing() {
    State local_state;
    auto lam = [&]() { return computeResult(local_state); };
    auto fut = boost::async(lam);
    return fut.then([&](auto&&) { return local_state.val; });  // 依然是悬挂引用
}

int main() {
    auto fun = doThing();
    // doThing返回后立刻污染栈空间,覆盖原local_state的内存
    pollute_stack();
    // 等待异步任务和延续任务执行完成
    int out = fun.get();
    // 正常预期输出是1,出现悬挂引用时会输出0xdeadbeef或者0xcccccccc等乱码,甚至直接崩溃
    std::cout << "最终读取值: " << out << std::endl;
    return 0;
}

效果说明

运行修改后的代码,大概率会输出乱码值而非预期的1,部分编译配置下会直接触发段错误,即可稳定复现文章中提到的悬挂引用风险。

内容的提问来源于stack exchange,提问作者fabian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 10:45:03