https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108565
Bug ID: 108565 Summary: -Wuse-after-free false positive on a shared_ptr implementation triggered by -O2 Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: egor_suvorov at mail dot ru Target Milestone: --- May or may not be a duplicate of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106119 Consider the following code, which is a subset of a shared_ptr's implementation: struct shared_ptr { int *counter_ = nullptr; int *data_ = nullptr; shared_ptr(int *data) : counter_(data ? new int(1) : nullptr), data_(data) { } shared_ptr(const shared_ptr &other) : counter_(other.counter_), data_(other.data_) { if (counter_ != nullptr) { ++*counter_; } } ~shared_ptr() { if (counter_ != nullptr) { --*counter_; if (*counter_ == 0) { delete counter_; delete data_; } } } }; void foo() { shared_ptr a(new int(10)); // should be non-nullptr shared_ptr b(a); shared_ptr c(new int(20)); // should be non-nullptr } int main() { foo(); } `g++ -std=c++17 -Wuse-after-free -O1` compiles this code without any problems, and it runs without memory leaks or double-frees. However, `g++ -std=c++17 -Wuse-after-free -O2` generates a bogus warning: In destructor 'shared_ptr::~shared_ptr()', inlined from 'void foo()' at x.cpp:27:1: x.cpp:15:15: warning: pointer used after 'void operator delete(void*, long long unsigned int)' [-Wuse-after-free] 15 | --*counter_; | ^~~~~~~~~ In destructor 'shared_ptr::~shared_ptr()', inlined from 'void foo()' at x.cpp:27:1: x.cpp:17:24: note: call to 'void operator delete(void*, long long unsigned int)' here 17 | delete counter_; | ^~~~~~~~ Seems like GCC is not smart enough to understand the underlying logic of 'shared_ptr'. Any of the following transformations remove the warning for me: * Replacing `new int(10)` or `new int(20)` with nullptr * Removing the ternary operator from `counter_`'s initialization. * Replacing `-O2` with `-O1` or `-O0` I've tested it both on trunk via Godbolt (https://godbolt.org/z/6ed1GY9Y7), and on my local GCC 12.2 (Windows, msys2) and GCC 12.1 (Ubuntu 22.04).