llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.05k stars 11.98k forks source link

StackAddressEscape doesn't properly lifetime extend temporaries bound to static variables #36895

Open gburgessiv opened 6 years ago

gburgessiv commented 6 years ago
Bugzilla Link 37547
Version trunk
OS Linux

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. :) )

gburgessiv commented 6 years ago

assigned to @devincoughlin