Wrong -Wstringop-overflow warning for std::array of vectors?
Georg-Johann Lay via Gcc-help <[email protected]> Fri, 13 Feb 2026 13:51:39 +0100
| Newsgroups | gmane.comp.gcc.help |
|---|---|
| Message-ID | <[email protected]> |
I am getting warnings like
main.cpp:45:15: warning: writing 1 byte into a region of size 0
[-Wstringop-overflow=]
45 | v_[i] = (Point::value_t) val;
| ~~~~~~^~~~~~~~~~~~~~~~~~~~~~
and am unsure whether it is a known PR or worth reporting as PR.
Attached is as C++17 test case that's compiled like:
$ g++ -c main.cpp -std=c++17 -fno-exceptions -W -Wall -O3 -fmax-errors=1
-o main.obj
In member function 'void Point::set(int, int)',
inlined from 'void Cluster::shift(int, int)' at main.cpp:135:19,
inlined from 'void Cluster::add(Point, bool)' at main.cpp:128:23,
inlined from 'Cluster::Cluster(const Cluster*, Point)' at
main.cpp:81:13,
inlined from 'int main()' at main.cpp:201:61:
main.cpp:45:15: warning: writing 1 byte into a region of size 0
[-Wstringop-overflow=]
45 | v_[i] = (Point::value_t) val;
| ~~~~~~^~~~~~~~~~~~~~~~~~~~~~
main.cpp: In function 'int main()':
main.cpp:201:61: note: at offset 8 into destination object '<anonymous>'
of size 8
201 | set[i].emplace (Cluster (&cs, Point::rand ()));
| ^
and more similar warnings.
I see these warnings with g++ 14 and also with current trunk from today
on x86_64 gnu/linux.
The test case is not preprocessed and includes only std headers.
When a pre-processed test case is needed I can provide one.
The test case defines a struct Point that's a vector type with 2 int8_t
components. It then defines a struct Cluster that's a std::array<Point,
1+CELLS> that can hold 0...CELLS Points. The number of Points in the
Cluster is stored in the last array element.
Some observations:
* I only see the warnings with -O3, with lower optimizations it goes away.
* The warning goes away when I add -fsanitize=address.
* The main function iterated over a std::set<Cluster>. When I adjust
the code to iterate over std::vector<Cluster> then the warning
also goes away.
best regards
Johann
main.cpp
(text/x-c++src, 5.3 KB)
#include <vector>
#include <set>
#include <array>
#include <iostream>
#include <cstdint>
#include <cstdlib>
#include <cassert>
#define DIM 2
#define CELLS 3
struct Point ///////////////////////////////////////////////////////////////////
{
using value_t = int8_t;
#if DIM == 2
using vector_t = value_t __attribute__((vector_size(2)));
using int_t = uint16_t;
#elif DIM > 2 && DIM <= 4
using vector_t = value_t __attribute__((vector_size(4)));
using int_t = uint32_t;
#elif DIM > 4 && DIM <= 8
using vector_t = value_t __attribute__((vector_size(8)));
using int_t = uint64_t;
#elif DIM > 8 && DIM <= 16
using vector_t = value_t __attribute__((vector_size(16)));
using int_t = unsigned __int128;
#else
#error DIM=?
#endif
vector_t v_ = (vector_t) (int_t) 0;
int size () const
{
return DIM;
}
void set (int i, int val)
{
#if 0
// ??? v_[i] = Gives a (wrong?) warning. Work around that.
vector_t w (v_);
w[i] = (Point::value_t) val;
v_ = w;
#else
v_[i] = (Point::value_t) val;
#endif
}
int operator [] (int i) const
{
return v_[i];
}
int cmp (Point d) const
{
for (int i = 0; i < size (); ++i)
if (v_[i] != d[i])
return v_[i] - d[i];
return 0;
}
static Point rand ()
{
Point d;
for (int j = 0; j < d.size (); ++j)
d.set (j, std::rand() % 100);
return d;
}
};
struct Cluster //////////////////////////////////////////////////////////////
{
struct Iterator;
struct CIterator;
std::array<Point, 1 + CELLS> a_;
Cluster () {}
Cluster (const Cluster *dad, Point d)
{
if (dad)
a_ = dad->a_;
add (d, 1);
}
Point operator [] (int i) const
{
return a_[i];
}
int size () const
{
int sz = (int) a_[CELLS][0];
assert (sz >= 0 && sz <= CELLS);
return sz;
}
void set_size (int sz)
{
assert (sz >= 0 && sz <= CELLS);
a_[CELLS].set (0, sz);
}
void insert (const Iterator &it, Point d)
{
const int pos = (int) (& (*it) - & a_[0]);
assert (pos >= 0 && pos <= size ());
assert (pos < CELLS);
// Get a vacant Point at pos...
for (int i = size (); i > pos; --i)
a_[i] = a_[i - 1];
// ...for insertion.
a_[pos] = d;
set_size (1 + size ());
}
void add (Point d, bool assert_add)
{
for (auto it = begin (); ; ++it)
if (int i; it == end () || (i = d.cmp (*it)) < 0)
{
insert (it, d);
break;
}
else if (i == 0)
{
if (assert_add)
assert (i != 0 && "Assume we always increase cells");
break;
}
// Normalize again. Max one component of d is negative.
for (int j = 0; j < d.size (); ++j)
if (d[j] < 0)
{
shift (j, -d[j]);
break;
}
}
void shift (int i, int off)
{
for (Point &d : *this)
d.set (i, d[i] + off);
}
int cmp (const Cluster &c) const
{
auto &&p2 = c.begin ();
for (Point d : *this)
if (p2 == c.end ())
return 1;
else if (int i = d.cmp (*p2); i != 0)
return i;
else
++p2;
return p2 == c.end () ? 0 : -1;
}
bool operator == (const Cluster &r) const { return cmp (r) == 0; }
bool operator < (const Cluster &r) const { return cmp (r) < 0; }
bool contains (Point d) const
{
for (Point c : *this)
if (int i = c.cmp (d); i == 0)
return true;
else if (i > 0)
break;
return false;
}
struct Iterator
{
friend Cluster;
Point *ptr;
Iterator () = delete;
Iterator (Point *ptr) : ptr(ptr) {}
void operator ++ () { ++ptr; };
bool operator == (const Iterator &i) const { return ptr == i.ptr; }
bool operator != (const Iterator &i) const { return ptr != i.ptr; }
Point& operator * () const { return *ptr; }
};
struct CIterator
{
friend Cluster;
const Point *ptr;
CIterator () = delete;
CIterator (const Point *ptr) : ptr(ptr) {}
void operator ++ () { ++ptr; };
bool operator == (const CIterator &i) const { return ptr == i.ptr; }
bool operator != (const CIterator &i) const { return ptr != i.ptr; }
Point operator * () const { return *ptr; }
};
Iterator begin () { return Iterator (&a_[0]); }
Iterator end () { return Iterator (&a_[size ()]); }
CIterator begin () const { return CIterator (&a_[0]); }
CIterator end () const { return CIterator (&a_[size ()]); }
};
int main () /////////////////////////////////////////////////////////////////
{
std::vector<std::set<Cluster>> set (1 + CELLS);
for (int i = 1; i <= CELLS; ++i)
{
std::cout << "== " << i << " ==\n";
if (i == 1)
set[1].emplace (Cluster (nullptr, Point ()));
else
for (const Cluster &cs : set[i - 1])
set[i].emplace (Cluster (&cs, Point::rand ()));
std::cout << "#clusters = " << set[i].size() << "\n";
}
}