The following code emits a warning when using strncmp() to compare a small quoted string with a "char data[4]" array declared __attribute__((nonstring)). The warning only appears if the quoted string is smaller than the size of the data[] array. My use of the data[] array is intended to act like a NUL-terminated string unless it is 4 bytes long, at which point it is non-NUL-terminated. This is the expected behavior when using strncpy() to fill (and truncate) arbitrary strings into a fixed-sized char[] array. I understand I can let GCC know of this intent by marking the array with __attribute__((nonstring)). My anticipated fix for GCC is that this warning should only appear with strcmp() and not strncmp(). extern char *strncpy (char *, const char *, long); extern int strncmp (const char *, const char *, long); extern __attribute__((nonstring)) char data[4]; void test(char *string) { if(strncmp(data, "??", sizeof(data))) strncpy(data, string, sizeof(data)); } # gcc -O3 test.c -c -Wall test.c: In function ‘test’: test.c:8:6: warning: ‘__builtin_strcmp’ argument 1 declared attribute ‘nonstring’ [-Wstringop-overflow=] if(strncmp(data, "??", sizeof(data))) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ test.c:4:40: note: argument ‘data’ declared here Incidentally, changing the "??" to "????" or to a variable of type char* does not cause the warning. In my understanding, strncmp() is the correct function to use here because the size (3rd arg) does not overflow the length of data[4]. Nothing has overflowed here to warrant a stringop-overflow warning. I'm also unsure why the warning says '__builtin_strcmp' when strncmp() instead of strcmp() is being used. Removing the __attribute__((nonstring)) causes strncpy() to warn instead: extern char *strncpy (char *, const char *, long); extern int strncmp (const char *, const char *, long); extern char data[4]; void test(char *string) { if(strncmp(data, "??", sizeof(data))) strncpy(data, string, sizeof(data)); } # gcc -O3 test.c -c -Wall test.c: In function ‘test’: test.c:9:5: warning: ‘strncpy’ specified bound 4 equals destination size [-Wstringop-truncation] strncpy(data, string, sizeof(data)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Conclusion: If GCC 8+ intends that we mark non-NUL-terminated strings with __attribute__((nonstring)) going forward, then there needs to be a way to cleanly use strncmp() to compare strings saved with strncpy() without any warnings.
Confirmed with the simpler test case below. GCC transforms the strncmp() call to strcmp() because it can see that the bound is larger than the length of one of the arguments but the warning doesn't consider this case (i.e., it triggers even when the strcmp call cannot read past the end of the non-string array. $ cat b.c && gcc -O2 -S -Wall b.c extern __attribute__((nonstring)) char a[4]; int f (const char *s) { return __builtin_strcmp (a, "12"); } b.c: In function ‘f’: b.c:5:10: warning: ‘__builtin_strcmp’ argument 1 declared attribute ‘nonstring’ [-Wstringop-overflow=] return __builtin_strcmp (a, "12"); ^~~~~~~~~~~~~~~~~~~~~~~~~~ b.c:1:40: note: argument ‘a’ declared here extern __attribute__((nonstring)) char a[4]; ^
This should be easily fixable for the simple cases involving string constants. It may not be so simple for the non-constant ones.
Patch: https://gcc.gnu.org/ml/gcc-patches/2018-05/msg00509.html
Author: msebor Date: Tue May 22 17:45:35 2018 New Revision: 260541 URL: https://gcc.gnu.org/viewcvs?rev=260541&root=gcc&view=rev Log: PR c/85623 - strncmp() warns about attribute 'nonstring' incorrectly in -Wstringop-overflow gcc/ChangeLog: PR c/85623 * calls.c (maybe_warn_nonstring_arg): Use string length to set or ajust the presumed bound on an operation to avoid unnecessary warnings. gcc/testsuite/ChangeLog: PR c/85623 * c-c++-common/attr-nonstring-3.c: Adjust. * c-c++-common/attr-nonstring-4.c: Adjust. * c-c++-common/attr-nonstring-6.c: New test. Added: trunk/gcc/testsuite/c-c++-common/attr-nonstring-6.c Modified: trunk/gcc/ChangeLog trunk/gcc/calls.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/c-c++-common/attr-nonstring-3.c trunk/gcc/testsuite/c-c++-common/attr-nonstring-4.c
Patch committed to trunk in r260541.
Author: msebor Date: Mon Jun 4 15:35:49 2018 New Revision: 261152 URL: https://gcc.gnu.org/viewcvs?rev=261152&root=gcc&view=rev Log: PR c/85623 - strncmp() warns about attribute 'nonstring' incorrectly in -Wstringop-overflow gcc/ChangeLog: PR c/85623 * calls.c (maybe_warn_nonstring_arg): Use string length to set or ajust the presumed bound on an operation to avoid unnecessary warnings. gcc/testsuite/ChangeLog: PR c/85623 * c-c++-common/attr-nonstring-3.c: Adjust. * c-c++-common/attr-nonstring-4.c: Adjust. * c-c++-common/attr-nonstring-6.c: New test. Added: branches/gcc-8-branch/gcc/testsuite/c-c++-common/attr-nonstring-6.c Modified: branches/gcc-8-branch/gcc/ChangeLog branches/gcc-8-branch/gcc/calls.c branches/gcc-8-branch/gcc/testsuite/ChangeLog branches/gcc-8-branch/gcc/testsuite/c-c++-common/attr-nonstring-3.c branches/gcc-8-branch/gcc/testsuite/c-c++-common/attr-nonstring-4.c
Patch backported into 8-branch in r261152.