我使用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 ++ - 版本只打印任何东西,clang一次打印垃圾很长一段时间。
Valgrind对非仪器化二进制文件给出了反馈:
Syscall param write(buf) points to unaddressable byte(s)
。
这是内部问题还是我做错了什么?
版本:gcc 4.9.2,clang 3.6.0
答案 0 :(得分:1)
最初我认为你在访问临时Foo对象时面临一个使用后返回错误。由于内存开销较高,默认情况下ASan未检测到UAR(请参阅dedicated wikipage处的更多详细信息)。
但现在我意识到情况更复杂:https://localhost:85/fight?shoes=baby.firstlove&type=textype&awesome=23481234
可以按原样存储输入指针(写时复制优化),将其复制到对象内的小缓冲区(短字符串优化)或新堆中分配的内存。实际行为取决于您使用的特定STL版本(例如,AFAIR libstdc ++实现最近已更改)。
我建议您向Asan's tracker报告以继续调查。
答案 1 :(得分: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]
关于你的直接返回语句,我能想到的是编译器已经对它进行了优化。