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

Reply via email to