Ошибка дезинфицирующего устройства адреса
Я немного использую встроенные дезинфицирующие средства 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++- версия просто ничего не печатает, лягушка один печатает мусор долгое время.
Valgrind на неинструментированном бинарном файле дает обратную связь:Syscall param write(buf) points to unaddressable byte(s)
,
Это внутренняя проблема асана или я делаю что-то не так?
Версии: gcc 4.9.2, clang 3.6.0
2 ответа
Первоначально я думал, что вы сталкиваетесь здесь с ошибкой использования после возврата при доступе к временному объекту Foo. UAR не распознаются ASan по умолчанию из-за больших накладных расходов памяти (подробности см. На специальной вики-странице).
Но теперь я понял, что ситуация более сложная: std::string может хранить входной указатель как есть (оптимизация копирования при записи), копировать его в небольшой буфер внутри объекта (оптимизация короткой строки) или в новую выделенную кучу память. Реальное поведение зависит от конкретной используемой версии STL (например, реализация AFAIR libstdC++ недавно изменилась).
Я предлагаю вам сообщить об этом следопыту Асана, чтобы продолжить расследование там.
#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, я могу думать о том, что компилятор уже оптимизировал его.