This code has undefined behavior:
#include <string>
std::string make_str(const char* s)
{
return s;
}
const char* get_str(const std::string& s)
{
return s.c_str();
}
const char* bad()
{
return get_str(make_str("hello"));
}
The bad function creates a temporary std::string and returns a pointer to its data, which is invalid as soon as the function has returned.
GCC 5+ catches this ("function returns address of local variable") but only if compiling with -O3
. At more typical optimization levels including -O2
, GCC compiles it without complaint, even with -Wall -Wextra
. Clang never catches it unless you use the experimental -Wlifetime
feature.
My question is: Can we tell the compiler explicitly about such lifetime dependencies, e.g. using an attribute? For example, I would like to be able to do this:
[[lifetime-depends : s]] // hypothetical syntax
const char* get_str(const std::string& s);
Or maybe this:
const char* get_str(const std::string& s)
__attribute__((lifetime-depends(0))); // hypothetical syntax
I'll accept an answer that works with any official release of GCC or Clang, but prefer GCC 6.1 with C++14. Clang's experimental -Wlifetime
is not an answer, because I want to be explicit, not rely on heuristics (which seemingly wouldn't work across multiple translation units anyway).
Alternatively, I'll accept an answer providing reasons why this wouldn't be useful or feasible to implement.
IMHO that would imply a quite immense reliability on compiler intelligence to catch user errors, because that is the code you posted, a failure. The standard already covers how to handle lifetimes of temporaries and does consider extending the lifetime in cases the reference is still in use (see draft n4713 eg. 15.2 Bullet 5). However, your posted example is a different case...
Also, while the Paper p1179r0 (comment by P.W) does provide an idea for pointers to objects stored on the stack it does not help with objects on the heap. And how should it? Returning a pointer to char (or any type) is not an error... returning a pointer to an array which does not exist anymore, is. How should it know c_str() returns a pointer to an array of a temporary wich does delete in it's destructor (kinda specific, isn't it?)? How to know if the array is destroyed? By looking into the destructor if a delete is done? What if the destructor does not delete? Warn about destructor should delete? What if the new
was a placement new? What if.... factory pattern...? What if creating pointers for smart pointer (e.g: shared_ptr)...? What if another 200 points... Managing lifetime on the heap, would mostly result in garbage collection.
The warning you get is function returns address of local variable [-Wreturn-local-addr]
which, I think, has nothing to do with your code, but is more an "accident" caused by short string optimization. SSO optimized std::string
does return a pointer to a local as the message says... Simple test, make your string longer than 16 chars, the warning disappears...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With