Mr Pang
Mr Pang

Reputation: 1181

What is the life cycle of a class instance returned by function?

Here's a program:

#include <cstring>
#include <iostream>
#include <string>
std::string fun(){
    return "this is a string";
}
int main(){
    const char *str = fun().c_str();
    if(strcmp(str, "this is a string1") == 0){
        std::cout << "ok" << std::endl;
    }
}

When I compiled with AddressSanitizer, I got:

=================================================================
==1841==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000000010 at pc 0x7ffff7658c18 bp 0x7fffffffd800 sp 0x7fffffffcfa8
READ of size 1 at 0x603000000010 thread T0
    #0 0x7ffff7658c17  (/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/libasan.so.6+0x8cc17)
    #1 0x555555556500 in main /home/pqy/src/json/include/t.cpp:9
    #2 0x7ffff7073ed9 in __libc_start_main ../csu/libc-start.c:314
    #3 0x5555555561c9 in _start (/home/pqy/src/json/include/tt+0x21c9)

0x603000000010 is located 0 bytes inside of 17-byte region [0x603000000010,0x603000000021)
freed by thread T0 here:
    #0 0x7ffff767ce37 in operator delete(void*) (/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/libasan.so.6+0xb0e37)
    #1 0x5555555564d6 in main /home/pqy/src/json/include/t.cpp:8
    #2 0x7ffff7073ed9 in __libc_start_main ../csu/libc-start.c:314

previously allocated by thread T0 here:
    #0 0x7ffff767c317 in operator new(unsigned long) (/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/libasan.so.6+0xb0317)
    #1 0x7ffff74cfb6c in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag) (/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/libstdc++.so.6+0x16fb6c)

SUMMARY: AddressSanitizer: heap-use-after-free (/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/libasan.so.6+0x8cc17)

Why the std::string returned by fun() is destroyed so quickly since main function hasn't finished yet?

Upvotes: 1

Views: 56

Answers (1)

cigien
cigien

Reputation: 60218

In this statement:

const char *str = fun().c_str();
// oops, str is invalid, since the temporary has been destroyed

fun returns a temporary std::string, and you're taking a pointer to that with c_str. However, that temporary dies at the end of the full expression, in this case at the ;. So you're left with a pointer that points to memory that no longer exists, which is what the sanitizer is telling you about.


You can fix this by assigning the returned std::string to an l-value, and this will ensure that the pointer you take with c_str will live till the end of main.

auto temp = fun();
const char *str = temp.c_str();
// ok, str is valid, since temp has not been destroyed

Upvotes: 5

Related Questions