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();
}