I'm testing upgrading from GCC 9.3 to 10.2 and I'm seeing this new
warning:

  $ g++ --version
  x86_64-unknown-linux-gnu-g++ (GCC) 10.2.0
      ...

  $ g++ -Wall -Werror -O2 -c -o stringop.o stringop.cpp

  In member function 'void LeafNode::markUpdate()',
      inlined from 'void applyTo(LeafNode*)' at stringop.cpp:45:21:
  stringop.cpp:37:33: error: writing 1 byte into a region of size 0 
[-Werror=stringop-overflow=]
     37 |     void markUpdate() { flags() |= UPDATE; }
        |                         ~~~~~~~~^~~~~~~~~
  stringop.cpp: In function 'void applyTo(LeafNode*)':
  stringop.cpp:34:7: note: at offset 0 to object 'LeafNode::<anonymous>' with 
size 4 declared here
     34 | class LeafNode : public NodeWithPayload<LeafNodePayload>
        |       ^~~~~~~~
  cc1plus: all warnings being treated as errors

It could well be that this code is dodgy; I take no responsibility for
it :).  It's part of a very tricky and performance- and memory-
sensitive area of the software.

I've stripped out tons of stuff and gotten it down to this, which is
still probably not the minimal test case but is pretty small.  If, for
example, I take out the _sequence field in LeafNodePayload, it doesn't
give any warnings.

The repro case is provided below.  If people think this is actually a
bug I can file an issue.

-----------------------------------------------------
nclude <cstddef>
#include <cstdint>

constexpr unsigned char UPDATE = 0x4;

class Node
{
protected:
    static size_t actualSize(uint16_t keyLength, size_t alignment) {
        return alignment * (((offsetof(Node, key) + keyLength - 1) / alignment) 
+ 1);
    }

public:
    const uint16_t _keyLength;
    struct {} key;
};

template<typename PAYLOAD>
class NodeWithPayload : public Node
{
protected:
    PAYLOAD& getPayload() {
        return *(reinterpret_cast<PAYLOAD*>(reinterpret_cast<unsigned 
char*>(this) + Node::actualSize(_keyLength, alignof(PAYLOAD))));
    }
};

class LeafNodePayload
{
public:
    uint64_t _sequence;
    unsigned char _flags;
};

class LeafNode : public NodeWithPayload<LeafNodePayload>
{
public:
    void markUpdate() { flags() |= UPDATE; }

private:
    unsigned char& flags() { return getPayload()._flags; }
};

void applyTo(LeafNode* node)
{
    node->markUpdate();
}

Reply via email to