$ clang-tidy -checks=clang-analyzer-core.StackAddressEscape /tmp/f.cpp --
2 warnings generated.
/tmp/f.cpp:9:3: warning: Address of stack memory associated with temporary object of type 'Foo' returned to caller [clang-analyzer-core.StackAddressEscape]
return &f;
^
/tmp/f.cpp:9:3: note: Address of stack memory associated with temporary object of type 'Foo' returned to caller
/tmp/f.cpp:10:1: warning: Address of stack memory associated with temporary object of type 'Foo' is still referred to by the static variable 'f' upon returning to the caller. This will be a dangling reference [clang-analyzer-core.StackAddressEscape]
}
^
/tmp/f.cpp:10:1: note: Address of stack memory associated with temporary object of type 'Foo' is still referred to by the static variable 'f' upon returning to the caller. This will be a dangling reference
Reading the C++ standard, however, it appears that temporary lifetime extension extends the lifetime of temporaries to live as long as the reference they're being bound to. So, since f is static, the temporary being bound to it gets to live until the program dies: https://godbolt.org/g/snsWA7 (please note the atexit dtor call and extra global _ZGRZ3foovE1f_)
Extended Description
Test-case:
$ cat /tmp/f.cpp struct Foo { Foo(); ~Foo();
int i; };
const void *foo() { static const Foo &f = {}; return &f; }
$ clang-tidy -checks=clang-analyzer-core.StackAddressEscape /tmp/f.cpp -- 2 warnings generated. /tmp/f.cpp:9:3: warning: Address of stack memory associated with temporary object of type 'Foo' returned to caller [clang-analyzer-core.StackAddressEscape] return &f; ^ /tmp/f.cpp:9:3: note: Address of stack memory associated with temporary object of type 'Foo' returned to caller /tmp/f.cpp:10:1: warning: Address of stack memory associated with temporary object of type 'Foo' is still referred to by the static variable 'f' upon returning to the caller. This will be a dangling reference [clang-analyzer-core.StackAddressEscape] } ^ /tmp/f.cpp:10:1: note: Address of stack memory associated with temporary object of type 'Foo' is still referred to by the static variable 'f' upon returning to the caller. This will be a dangling reference
Reading the C++ standard, however, it appears that temporary lifetime extension extends the lifetime of temporaries to live as long as the reference they're being bound to. So, since
f
is static, the temporary being bound to it gets to live until the program dies: https://godbolt.org/g/snsWA7 (please note the atexit dtor call and extra global_ZGRZ3foovE1f_
)For added fun, this appears to apply to struct fields, too: https://godbolt.org/g/NdV7jW
(FWIW, the struct fields example is a reduced version of how I found this. When I first saw it, I thought the code was broken, too. :) )