3

I'm using gcc and clang-embedded sanitizers for a little, including address sanitizer. And things work pretty well, but on next demo code I get no output related to a error despite it is there (to be more precise -- no output at all):

#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;
}

I tried g++ -O0 -g -fsanitize=address test.cc and same with clang++: g++-version just prints nothing, clang one prints garbage for a long time. Valgrind on non-instrumented binary gives feedback: Syscall param write(buf) points to unaddressable byte(s).

Is it internal asan problem or I'm doing something wrong?

Versions: gcc 4.9.2, clang 3.6.0

Alexander Sergeyev
  • 922
  • 10
  • 19

2 Answers2

2

Originally I thought that you face a use-after-return bug here on accessing temporary Foo object. UARs are not detected by ASan by default due to high memory overhead (see more details at dedicated wikipage).

But now I realized that situation is more complicated: std::string may store input pointer as is (copy-on-write optimization), copy it to small buffer inside object (short string optimization) or to a new heap-allocated buffer. The actual behavior depends on particular STL version that you are using (e.g. AFAIR libstdc++ implementation has recently changed).

I suggest you to report it to Asan's tracker to continue investigation there.

yugr
  • 19,769
  • 3
  • 51
  • 96
  • Okay, that makes sense. Though I'm unable to get this to work still with clang-3.8.1-r100. I see a memory dump until a zero byte is hit when no sanitizer is in use; with the sanitizer I get a segfault (no use-after-return tracking); the sanitizer + uar-tracking = just the original string, like the stack was not reused, no messages about the problem. Has this feature fully landed in the later releases? – Alexander Sergeyev Oct 26 '16 at 07:48
  • Yes, the feature has been there for couple of years so should be quite robust. Note that I've updated my answer - depending on std::string implementation this can be either use-after-return or use-after-free. Either should be detected by Asan though so I suggest to report an issue to developers. – yugr Oct 26 '16 at 08:55
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;
}

Works fine if you remove the reference.

Also the object you're creating is only valid in bar() making it useless afterwards.

It works for your get method because the variable is pre existing in the scope of the class.


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

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

You will get a warning if you don't actually just return the reference but rather put it in a string for example:

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

What I can think of concerning your direct return statement is that the compiler already optimized it out.

deW1
  • 5,562
  • 10
  • 38
  • 54
  • Yup, I know. Problem is not in the code itself, but in sanitizer behavior. – Alexander Sergeyev Apr 15 '15 at 17:05
  • Okay, but it's interesting that compiler won't warn you even with -Wall -Wpedantic flags -- with that direct return. So compiler optimized out return statement in bar() function, but dangling reference is still there and sanitizer hasn't managed to catch its access. And last is the problem. – Alexander Sergeyev Apr 15 '15 at 17:18