Я немного использую встроенные дезинфицирующие средства 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
Первоначально я думал, что вы сталкиваетесь с ошибкой использования после возврата при доступе к временному объекту 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, я могу думать о том, что компилятор уже оптимизировал его.