gpt4 book ai didi

c++ - 地址 sanitizer 有时会错过释放后的堆使用

转载 作者:行者123 更新时间:2023-11-28 04:05:04 25 4
gpt4 key购买 nike

在调整大小的 vector 元素上保留一个指针,然后取消引用它是未定义的行为。

在以下程序中使用 std::vector<int> 测试这种不良做法时(与 #if 0 ),地址清理器正确报告释放后堆使用错误。

$ ./prog
capa: 8
v[0]: 0x603000000010 <1000>
p: 0x603000000010 <1000>
capa: 16
v[0]: 0x6060000000e0 <1000>
=================================================================
==23068==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000000010

但是当用 std::vector<std::string> 尝试相同的实验时(与 #if 1 ),地址清理器不报告任何内容,这会导致使用已销毁的字符串(可能在调整大小期间移动)通过指针!

$ ./prog
capa: 8
v[0]: 0x611000000040 <1000>
p: 0x611000000040 <1000>
capa: 16
v[0]: 0x615000000080 <1000>
p: 0x611000000040 <>

我的问题:为什么地址 sanitizer 在第二种情况下不报告错误?
编辑:valgrind 报告错误。

我在 GNU/Linux x86_64 (Archlinux) 上使用 g++ 9.2.0 和 clang++ 9.0.0 测试了以下程序。

/**
g++ -std=c++17 -o prog prog.cpp \
-pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#include <iostream>
#include <vector>

#if 1
# include <string>
inline auto make_elem(int n) { return std::to_string(n); }
#else
inline auto make_elem(int n) { return n; }
#endif

using elem_t = decltype(make_elem(0));

inline
void
fill(std::vector<elem_t> &v,
int sz)
{
v.resize(std::size_t(sz));
for(auto i=0; i<sz; ++i)
{
v[i]=make_elem(1000+i);
}
}

inline
void
show(const std::vector<elem_t> &v,
const elem_t *p)
{
std::cout << "capa: " << v.capacity() << '\n';
std::cout << "v[0]: " << &v[0] << " <" << v[0] << ">\n";
std::cout << "p: " << p << " <" << *p << ">\n"; // <-- possible invalid pointer here
}

int
main()
{
constexpr auto sz=8;
auto v=std::vector<elem_t>{};
fill(v, sz);
const auto *p=data(v);
show(v, p);
fill(v, 2*sz);
show(v, p);
return 0;
}

我还提交了 upstream bug关于这个。

最佳答案

我对 github 问题发表了评论,但简短的回答是,由于 libstdc++.so.6 拆分某些常见模板实例的方式,例如

basic_ostream<...>::operator<<(basic_ostream<...>&, const std::string &);

并仅在 libstdc++.so.6 中实例化它们一次,并且因为 libstdc++.so.6 本身不是 asan-instrumented,所有被检测的代码可以看到的是您正在将悬空指针传递给外部函数。它不知道外部函数将如何处理这个指针,因此无法报告错误。

问题不会clang++ ... -stdlib=libc++ 重现(正确报告悬空访问)。

关于c++ - 地址 sanitizer 有时会错过释放后的堆使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58867953/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com