https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94335
Bug ID: 94335 Summary: False positive -Wstringop-overflow warning with -O2 Product: gcc Version: 10.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: romain.geissler at amadeus dot com Target Milestone: --- Hi, The following code emits a false positive -Wstringop-overflow warning with gcc trunk with -O2 and -O3. It's reduced manually from a much more complex scenario, where we try to define an iterator that can be stored in shared memory, thus referencing object through relative addresses rather than absolute addresses. In the warning of this scenario, I don't see how we can access offset -424242 as the initial pointed address is never nullptr. Note: gcc 8/9 do not emit such warning. #include <iterator> #include <memory> #include <cassert> #include <limits> #include <cstring> template <class T> struct relative_address_iterator { typedef T value; typedef T *pointer; typedef const T *const_pointer; typedef T &reference; typedef const T &const_reference; typedef T value_type; typedef ptrdiff_t difference_type; typedef std::forward_iterator_tag iterator_category; off_t d; static constexpr off_t kEmptyPointer = std::numeric_limits<off_t>::min(); /** Constructs the object from a pointer. */ relative_address_iterator(pointer t) { if (t) { d = (char *)t - (char *)this; } else { d = kEmptyPointer; } } /** Copy constructor. */ relative_address_iterator(const relative_address_iterator &r) { if (r.d != kEmptyPointer) { d = (char *)&r - (char *)this + r.d; } else { // Normally this should not happen in this example, but gcc thinks it does, // as the error message references the special value -424242. // d = kEmptyPointer; d = -424242; } } /** Initializes the pointee with the given value. */ void setVal(const_reference value) { *(pointer)((char *)this + d) = value; } /** Dereferences the object. */ operator pointer() { if (d == kEmptyPointer) return nullptr; return ((pointer)((char *)this + d)); } /** Preincrement operator. */ relative_address_iterator &operator++() { d += sizeof(value); return (*this); } }; void f() { char* aDummyBuffer = static_cast<char*>(malloc(10)); memset(aDummyBuffer, 10, 0); relative_address_iterator<char> it(aDummyBuffer); relative_address_iterator<char> itCopy(it); itCopy.setVal('A'); char* aDummySource = static_cast<char*>(malloc(10)); memset(aDummySource, 10, 0); std::copy(relative_address_iterator<char>(aDummySource), relative_address_iterator<char>(aDummySource + 5), it); } int main() { f(); } In member function 'void relative_address_iterator<T>::setVal(relative_address_iterator<T>::const_reference) [with T = char]', inlined from 'void f()' at <source>:82:18: <source>:56:71: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=] 56 | void setVal(const_reference value) { *(pointer)((char *)this + d) = value; } | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~ <source>: In function 'void f()': <source>:80:37: note: at offset -424242 to object 'itCopy' with size 8 declared here 80 | relative_address_iterator<char> itCopy(it); | ^~~~~~ Compiler returned: 0 Cheers, Romain