(Edited: I oversimplified the original version, accessing S::x
as a public member rather than by getter.)
More than once I've had ASAN find bugs of this form:
#include <optional>
// Using optional as the example type because the UB
// seems to express as nullopt and throw.
struct S {
std::optional<int> x;
std::optional<int>& getX() { return x; }
};
inline S getS(int x) { return S{x}; }
// If we use this, below, it's OK because the S stays alive.
inline S& getSByRef(int x) {
static S s{};
s.x = x;
return s;
}
int main() {
const auto& x = getS(42).getX(); // If we do getS(42).x then it's OK because S's lifetime is extended.
return x.value(); //< Use after scope!
}
https://godbolt.org/z/vxoG6T58b
If I use getSByRef()
(returned by reference), this is fine (https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/). Likewise if I use getS(42).x
. But since getS()
returns by value, the temporary S
goes out of scope by the next line, meaning the reference is dangling. ASAN can see these, but this seems like an obvious thing the compiler could catch, like it catches returning a local by reference (https://godbolt.org/z/1hjKPf5vM).
Is there a tool that can statically catch this?