https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84468
Bug ID: 84468 Summary: [gcc 8] Inconsistent -Wstringop-truncation warnings with -O2 Product: gcc Version: 8.0.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: romain.geissler at amadeus dot com Target Milestone: --- Hi, I can see some strange behavior for the warning -W=stringop-truncation with -O2 and current master, depending on how I enclose my code in if/else blocks or not, despite that logically speaking, the end result is always the same. See this code: EOF #include <string.h> class A { public: A(); A(const char* iCString); A& operator=(const A& iA); private: void setCString(const char* iCString); // Uncommenting the attribute silences the warning // but actually we do have a "string", not a "nonstring". /* [[gnu::nonstring]] */ char _cstring[3 + 1]; }; A::A() { _cstring[0] = '\0'; } A::A(const char* iCString) { setCString(iCString); } A& A::operator=(const A& iA) { if (this != &iA) // Commenting this line silences the warning. { setCString(iA._cstring); } return *this; } void A::setCString(const char* iCString) { // This version produces warning. if (iCString) { strncpy(_cstring, iCString, 3); } _cstring[3] = '\0'; /* // This version doesn't produce any warning, but has the same logic as above. if (iCString) { strncpy(_cstring, iCString, 3); _cstring[3] = '\0'; } else { _cstring[3] = '\0'; } */ /* // This version also produces a warning, despite having the same logic as above, // just with an extra assigment to _cstring[3] when iCString is not null. if (iCString) { strncpy(_cstring, iCString, 3); _cstring[3] = '\0'; } _cstring[3] = '\0'; */ } When compiled with -Wall -Werror -Wextra -std=gnu++17 -O2 and current master. I get: error: ‘char* strncpy(char*, const char*, size_t)’ output may be truncated copying 3 bytes from a string of length 3 [-Werror=stringop-truncation] First what I find strange is the warning itself. gcc is clever enough to see that source is 3 bytes long, that we copy in a buffer that is 4 bytes long, so why would it complain about a truncation anyway ? Or maybe I misunderstood the wording of the warning itself ? Second, why are the different variant of A::setCString I commented in the code working differently wrt the warning, while logically speaking they do have the same behavior. If we need to write our if/else block in a given way to make gcc understand it is safe, this starts to be complex for developers. Final question: do you think it would somehow make sense to introduce a "string" attribute, that would be the contrary of the newly introduced "nonstring". "nonstring" means that maybe the string is not null terminate. "string" would mean that for sure the array is always null terminated, and thus doing things like strncpy(_cstring, anotherA._cstring, 4) (note that I used 4 and not 3 for the total size), would always work ? "nonstring" correctly silences the warning, but has the exact opposite semantic meaning than I have in this particular case. Cheers, Romain