https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92893
Bug ID: 92893 Summary: Unhelpful -Wstringop-overflow warning Product: gcc Version: 10.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: sbergman at redhat dot com Target Milestone: --- Recent GCC 10 trunk produces a -Wstringop-overflow warning that at least gcc-c++-9.2.1-1.fc31.x86_64 does not produce. Unfortunately the minimal reproducer I came up with is still a bit lengthy: > $ cat test.cc > #include <cstring> > > struct View { > View(char const * s): s_(s), n_(std::strlen(s)) {} > char const * s_; > std::size_t n_; > }; > > template<typename T> struct Add { > static char * add(char * buf, T const &); > }; > > template<int N> struct Add<char const[N]> { > static char * add(char * buf, char const s[N]) { > std::memcpy(buf, s, N); > return buf + N; > } > }; > > template<> struct Add<View> { > static char * add(char * buf, View const & v) { > std::memcpy(buf, v.s_, v.n_); > return buf + v.n_; > } > }; > > template<typename T1, typename T2> struct Cat { > Cat(T1 const & x, T2 const & y): x_(x), y_(y) {} > char * add(char * buf) const > { return Add<T2>::add(Add<T1>::add(buf, x_), y_); } > T1 const & x_; > T2 const & y_; > }; > > template<typename T1, typename T2> struct Add<Cat<T1, T2>> { > static char * add(char * buf, Cat<T1, T2> const & c) { return c.add(buf); } > }; > > Cat<char const[1], View> catA(char const(&x)[1], View const & y) { > return {x, y}; > } > > Cat<Cat<char const[1], View>, char const[4]> catB( > Cat<char const[1], View> const & x, char const (&y)[4]) > { > return {x, y}; > } > > struct Buf { char buf[1]; }; > > Buf * get(); > > struct Str { > template<typename T1, typename T2> Str(Cat<T1, T2> c) > { c.add(get()->buf); } > }; > > void f(char const * p) { Str(catB(catA("", View(p)), "xxx")); } > $ g++ -O2 -c test.cc > In member function ‘char* Cat<T1, T2>::add(char*) const [with T1 = Cat<const > char [1], View>; T2 = const char [4]]’, > inlined from ‘Str::Str(Cat<T1, T2>) [with T1 = Cat<const char [1], View>; > T2 = const char [4]]’ at test.cc:55:10, > inlined from ‘void f(const char*)’ at test.cc:58:26: > test.cc:15:16: warning: writing 4 bytes into a region of size 1 > [-Wstringop-overflow=] > 15 | std::memcpy(buf, s, N); > | ~~~~~~~~~~~^~~~~~~~~~~ The warning only appears with this specific case where catB takes a char[4], not for other char[N]. Buff::buf is meant to be a trailing flexible array member. In the original code, it needs to stay that way for compatibility reasons, but also if it is replaced with the canonical GCC-extended flexible array member syntax, > struct Buf { char buf[0]; }; the warning remains (this time as "writing 4 bytes into a region of size 0"). At least in the original code, I found no range of code that could be wrapped in > #pragma GCC diagnostic push > #pragma GCC diagnostic ignored "-Wstringop-overflow" [...] > #pragma GCC diagnostic push short of disabling the warning completely. But maybe there is a way to annotate the call to c.add(get()->buf) in the Str constructor, to break the connection that Buf::buf is nominally of size 1 there?