【问题标题】:Address sanitizer failure地址消毒剂故障
【发布时间】:2015-04-15 16:47:14
【问题描述】:

我正在使用 gcc 和嵌入 clang 的消毒剂,包括地址消毒剂。一切运行良好,但在下一个演示代码中,尽管存在错误,但我没有得到与错误相关的输出(更准确地说 - 根本没有输出):

#include <string>
#include <iostream>

using std::string;
using std::cout;

class Foo
{
    string _member;
public:
    Foo(): _member("just a string") {}
    const string& get() const { return _member; }
};

const string& bar()
{
    // returning reference to a temp object on stack
    return Foo().get();
}

int main()
{
    cout << bar() << '\n';
    return 0;
}

我试过g++ -O0 -g -fsanitize=address test.ccclang++ 一样:g++-version 什么都不打印,clang 打印了很长时间的垃圾。 Valgrind 在非仪器二进制上给出反馈: Syscall param write(buf) points to unaddressable byte(s).

是内部问题还是我做错了什么?

版本:gcc 4.9.2、clang 3.6.0

【问题讨论】:

  • 您想知道为什么您的消毒剂会失败或您的代码有什么问题吗?
  • @honk,这是带有预期错误的演示代码。我对消毒剂静音感兴趣。

标签: c++ g++ clang++ sanitizer


【解决方案1】:

最初我认为您在访问临时 Foo 对象时会遇到一个返回后使用错误。由于高内存开销,ASan 默认不会检测到 UAR(请参阅dedicated wikipage 的更多详细信息)。

但现在我意识到情况更复杂:std::string 可以按原样存储输入指针(写时复制优化),将其复制到对象内的小缓冲区(短字符串优化)或新的堆分配缓冲。实际行为取决于您使用的特定 STL 版本(例如,AFAIR libstdc++ 实现最近已更改)。

我建议你向Asan's tracker报告,以便在那里继续调查。

【讨论】:

  • 好吧,这很有道理。虽然我无法让它与 clang-3.8.1-r100 一起工作。当没有使用消毒剂时,我看到一个内存转储,直到一个零字节被命中;使用消毒剂我得到一个段错误(返回后没有使用跟踪); sanitizer + uar-tracking = 只是原始字符串,就像堆栈没有被重用,没有关于问题的消息。此功能是否已在以后的版本中完全落地?
  • 是的,该功能已经存在了几年,所以应该非常强大。请注意,我已经更新了我的答案 - 根据 std::string 的实现,这可以是 use-after-return 或 use-after-free。两者都应该被 Asan 检测到,所以我建议向开发人员报告问题。
【解决方案2】:
#include <string>
#include <iostream>

using std::string;
using std::cout;

class Foo
{
    string _member;
public:
    Foo(): _member("just a string") {}
    const string& get() const { return _member; }
};

const string bar()
{
    // returning reference to a temp object on stack
    return Foo().get();
}

int main()
{
    cout << bar() << '\n';
    return 0;
}

如果您删除参考,效果很好。

此外,您正在创建的对象仅在 bar() 中有效,之后将变得无用。

它适用于您的 get 方法,因为该变量预先存在于类的范围内。


const string& bar()
{
    const string a = Foo().get();

    // returning reference to a temp object on stack
    return a;
}

如果您实际上不只是返回引用而是将其放在字符串中,例如,您将收到警告:

main.cpp:23:12: warning: reference to stack memory associated with local variable 'a' returned [-Wreturn-stack-address]

关于您的直接 return 语句,我能想到的是编译器已经对其进行了优化。

【讨论】:

  • 是的,我知道。问题不在于代码本身,而在于消毒剂的行为。
  • 好的,但有趣的是,即使使用 -Wall -Wpedantic 标志,编译器也不会警告你——直接返回。因此编译器优化了 bar() 函数中的 return 语句,但悬空引用仍然存在,并且 sanitizer 没有设法捕获它的访问权限。最后是问题。
猜你喜欢
  • 2021-03-06
  • 2016-07-28
  • 2017-09-17
  • 2023-03-23
  • 1970-01-01
  • 2019-09-05
  • 1970-01-01
  • 2021-03-07
  • 2021-02-08
相关资源
最近更新 更多