Reputation: 1181
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
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