0

我正在使用 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.cc了,同样的clang++:g++-version 什么都不打印,clang 一个打印垃圾很长一段时间。Valgrind 在非仪器二进制上给出反馈: Syscall param write(buf) points to unaddressable byte(s).

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

版本:gcc 4.9.2、clang 3.6.0

4

2 回答 2

1

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

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

我建议您将其报告给Asan 的跟踪器以继续在那里进行调查。

于 2016-10-24T13:31:48.160 回答
0
#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 语句,我能想到的是编译器已经对其进行了优化。

于 2015-04-15T17:01:31.717 回答