Bug 107694

Summary: Bogus stringop-overflow warning in gcc 12
Product: gcc Reporter: Mike Hommey <mh+gcc>
Component: tree-optimizationAssignee: Not yet assigned to anyone <unassigned>
Status: UNCONFIRMED ---    
Severity: normal CC: sjames, sylvestre
Priority: P3 Keywords: diagnostic
Version: 12.2.0   
Target Milestone: ---   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109571
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed:
Bug Depends on:    
Bug Blocks: 88443    

Description Mike Hommey 2022-11-15 09:08:31 UTC
Reproducer:
```
#include <atomic>

class nsISupports {
public:
  virtual int Release();
};
struct JSPrincipals {
  std::atomic<int> refcount;
};
class nsJSPrincipals : nsISupports, JSPrincipals {
  static nsJSPrincipals* get(JSPrincipals* principals) {
    return static_cast<nsJSPrincipals*>(principals);
  }
  void Destroy(JSPrincipals* jsprin);
};

void nsJSPrincipals::Destroy(JSPrincipals* jsprin) {
 nsJSPrincipals* nsjsprin = nsJSPrincipals::get(jsprin);
 nsjsprin->refcount.fetch_add(1, std::memory_order_acq_rel);
 nsjsprin->Release();
}
```

Compile with: g++ -c -O2 -Werror=stringop-overflow

It says:
```
In file included from /builds/worker/fetches/gcc/include/c++/12.2.0/atomic:41,
                 from Unified_cpp_caps0.ii.cpp:1:
In member function 'std::__atomic_base<_IntTp>::__int_type std::__atomic_base<_IntTp>::fetch_add(__int_type, std::memory_order) [with _ITp = int]',
    inlined from 'void nsJSPrincipals::Destroy(JSPrincipals*)' at Unified_cpp_caps0.ii.cpp:19:30:
/builds/worker/fetches/gcc/include/c++/12.2.0/bits/atomic_base.h:618:34: error: 'unsigned int __atomic_fetch_add_4(volatile void*, unsigned int, int)' writing 4 bytes into a region of size 0 overflows the destination [-Werror=stringop-overflow=]
  618 |       { return __atomic_fetch_add(&_M_i, __i, int(__m)); }
      |                ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
cc1plus: some warnings being treated as errors
```
Comment 1 Andrew Pinski 2023-05-19 04:37:50 UTC
PR 109571 is basically the same here just with a different warning (and upcasting instead of downcasting).

In this case if we look at:
void nsJSPrincipals::Destroy(JSPrincipals* jsprin) {
 nsJSPrincipals* nsjsprin = nsJSPrincipals::get(jsprin);


if jsprin is null, then nsjsprin needs to be null too. And since nsjsprin == jsprin-8(bytes) (if it was a valid pointer), the C++ front-end needs to add a check for null. And then the optimizations come along and does jump threading.
so one way of removing this is adding an assumption which can be done via one of the following:
  if (!jsprin) __builtin_unreachable();
  [[assume(jsprin)]];

The first one is valid for GCC all the way back in 4.7 (and before).
the second one is C++23 and was only added in GCC 13.