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

将tuple<int*,int,int,int*>转换为tuple<void*,int,int,void*>引发ASAN栈越界问题

ASAN栈使用越界(STACK USE AFTER SCOPE)问题分析

问题重现

以下代码调用f()时,会被ASAN检测到STACK USE AFTER SCOPE错误,触发点在Data::execute()访问m_tupleData的位置:

#include <iostream>
#include <tuple>

using TupleData = std::tuple<void *, int, int, void *>;

namespace
{
   int x = 1, y = 2, z = 3, v = 4; // 文件作用域变量
}

struct Data
{
   Data(const TupleData & tupleData) : m_tupleData(tupleData) {}

   const TupleData & m_tupleData;

   void execute()
   {
       void * int1 = std::get<0>(m_tupleData); // ASAN在此处检测到栈越界
   }
};

void f()
{       
   Data data(std::make_tuple(&x, y, z, &v)); 

   data.execute();
}

int main() {
    
    f();

    return 0;
}

尝试过程

  1. 先创建元组再传入,问题依旧(注:原代码遗漏逗号,此处已修正):
void f()
{       
   auto tupleData = {&x, y, z, &v};

   Data data(tupleData); 

   data.execute();
}
  1. 显式声明元组为TupleData类型后,问题解决:
void f()
{       
   TupleData tupleData = {&x, y, z, &v};

   Data data(tupleData); 

   data.execute();
}

问题原因

核心问题在于临时对象的生命周期与悬空引用:

  • 用std::make_tuple(&x, y, z, &v)时,返回的是std::tuple<int*, int, int, int*>类型对象。而Data构造函数接受的是const TupleData&(即std::tuple<void*, int, int, void*>的引用),编译器会自动创建一个临时的TupleData对象——通过int*类型元组隐式转换而来(int*转void*确实合法)。

  • 但C++中,绑定到函数参数的临时对象,生命周期仅延续到当前表达式结束。也就是Data data(...)执行完后,这个临时TupleData对象就会被销毁,而Data的m_tupleData引用的正是已销毁的对象。后续调用data.execute()时访问悬空引用指向的内存,就触发了ASAN的栈越界检测。

  • 用auto tupleData = {&x, y, z, &v}时,auto推导类型为std::initializer_list,传给Data构造函数时同样会构造临时TupleData对象,最终还是出现悬空引用问题。

  • 显式声明TupleData tupleData = {&x, y, z, &v}时,tupleData是f()栈上的局部对象,生命周期和data一致,直到f()执行完毕才销毁。此时m_tupleData引用的是存活对象,访问不会触发越界错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 12:06:00