简体   繁体   English

address sanitizer 有时会错过 heap-use-after-free

[英]address sanitizer sometimes misses heap-use-after-free

Keeping a pointer on an element of a vector which is resized and dereferencing it afterwards is undefined behavior.将指针保留在调整大小的向量元素上并在之后取消引用它是未定义的行为。

When testing this bad practice on the following program with a std::vector<int> (with #if 0 ), the address sanitizer correctly reports a heap-use-after-free error.在使用std::vector<int> (使用#if 0 )在以下程序上测试这种不良做法时,地址清理程序会正确报告 heap-use-after-free 错误。

$ ./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

But when trying the same experiment with std::vector<std::string> (with #if 1 ), the address sanitizer does not report anything, which leads to using a destroyed string (probably moved-from during the resize) through the pointer!但是,当使用std::vector<std::string> (使用#if 1 )尝试相同的实验时,地址清理程序不会报告任何内容,这会导致通过指针!

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

My question: why does not the address sanitizer report the error in this second case?我的问题:为什么地址清理程序在第二种情况下不报告错误?
edit: valgrind reports the error.编辑:valgrind 报告错误。

I tested the following program on GNU/Linux x86_64 (Archlinux) with g++ 9.2.0 and clang++ 9.0.0.我使用 g++ 9.2.0 和 clang++ 9.0.0 在 GNU/Linux x86_64 (Archlinux) 上测试了以下程序。

/**
  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;
}

I've also filed upstream bug about this.我还为此提交了上游错误

I've commented on github issue, but the short answer is that due to the way libstdc++.so.6 splits certain common template instantiations, such as我对 github 问题发表了评论,但简短的回答是由于libstdc++.so.6拆分某些常见模板实例的方式,例如

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

and instantiates them only once inside libstdc++.so.6 , and because libstdc++.so.6 itself is not asan-instrumented, all that instrumented code can see is that you are passing a dangling pointer into an external function.并且只在libstdc++.so.6内实例化它们一次,并且由于libstdc++.so.6本身不是作为仪表化的,所有仪表化代码可以看到的是您正在将一个悬空指针传递给外部 function。 It doesn't know what the external function will do with this pointer, and so can't report the error.不知道外部的function会用这个指针做什么,所以不能报错。

The problem does not reproduce with clang++... -stdlib=libc++ (dangling access is properly reported).使用 clang++无法重现该问题clang++... -stdlib=libc++ (已正确报告悬空访问)。

By default Asan detects overflows in buffers allocated with malloc .默认情况下,Asan 检测使用malloc分配的缓冲区中的溢出。 Vector's methods ( push_back , clear , resize , etc.) may or may not call malloc / free depending on element size, current capacity, etc. so Asan will often miss vector (or any other STL container) overflows. Vector 的方法( push_backclearresize等)可能会或可能不会调用malloc / free ,具体取决于元素大小、当前容量等,因此 Asan 经常会错过 vector(或任何其他 STL 容器)溢出。

Recent versions of Asan got better STL support (at least for std::vector and std::string ) and can detect accesses outside of container's "logical" bounds.最近版本的 Asan 获得了更好的 STL 支持(至少对于std::vectorstd::string )并且可以检测容器“逻辑”边界之外的访问。 These checks are enabled by default in Clang but not in GCC (you need to compile with -D_GLIBCXX_SANITIZE_STD_ALLOCATOR=1 there).这些检查在 Clang 中默认启用,但在 GCC 中未启用(您需要在此处使用-D_GLIBCXX_SANITIZE_STD_ALLOCATOR=1进行编译)。 Enabling this feature may introduce false positives so GCC's approach is IMHO safer.启用此功能可能会引入误报,因此 GCC 的方法恕我直言更安全。

As a side note, it's risky to test Asan's functionality with simple programs like this one.作为旁注,使用像这样的简单程序测试 Asan 的功能是有风险的。 Modern compilers will often often detect and optimize out obviously UB code at early phases, sometimes even at -O0 (hopefully with a warning so bug won't go unnoticed) before Asan instrumentation is added so Asan has no chance of detecting the bug.现代编译器通常会在早期阶段经常检测和优化明显的 UB 代码,有时甚至在-O0时(希望有警告,因此错误不会被 go 忽视)在添加 Asan 工具之前,因此 Asan 没有机会检测到错误。 You can prevent unwanted "optimizations" with __attribute__((noinline,noclone)) , inline asm, separate compilation, etc.您可以使用__attribute__((noinline,noclone)) 、内联汇编、单独编译等来防止不需要的“优化”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 可变内容导致 AddressSanitizer: heap-use-after-free on address - Variadic content leads to AddressSanitizer: heap-use-after-free on address BST释放后使用堆错误中的删除节点 - Delete Node in BST heap-use-after-free error AddressSanitizer:特定输入的 heap-use-after-free 错误 - AddressSanitizer: heap-use-after-free error for particular input 将变量声明为引用时的堆使用后释放 - heap-use-after-free when declaring a variable as a reference ASan:在递归 function 中的 vector.emplace(push)_back 之后的堆使用后释放 - ASan: heap-use-after-free after vector.emplace(push)_back in a recursive function 在 C++ 中使用带有 2D 向量的引用时,堆使用后释放 - heap-use-after-free when using references with 2D vector in C++ AddressSanitizer 识别 std::vector<t> ::push_back 作为 heap-use-after-free 错误的原因</t> - AddressSanitizer identifies std::vector<T>::push_back as reason for heap-use-after-free error ASAN:将二叉树展平到链接列表时释放后使用堆 - ASAN: heap-use-after-free when flattening a binary tree to a linked list 使用 std::vector 时的简单 Boost UDP 接收器 gest heap-use-after-free - Simple Boost UDP receiver gest heap-use-after-free when using std::vector 这是我为添加二进制 leet 代码而制作的程序,显示运行时错误:heap-use-after-free on adress - this is a program i made for adding binary leet code is showing an error that is runtime error:heap-use-after-free on adress
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM