Bug 85623 - strncmp() warns about attribute 'nonstring' incorrectly in -Wstringop-overflow
Summary: strncmp() warns about attribute 'nonstring' incorrectly in -Wstringop-overflow
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 8.1.0
: P3 normal
Target Milestone: ---
Assignee: Martin Sebor
URL:
Keywords: diagnostic, patch
Depends on:
Blocks:
 
Reported: 2018-05-03 03:13 UTC by gandalf
Modified: 2018-06-04 15:37 UTC (History)
1 user (show)

See Also:
Host:
Target: i686-pc-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed: 2018-05-08 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description gandalf 2018-05-03 03:13:10 UTC
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.
Comment 1 Martin Sebor 2018-05-08 02:46:36 UTC
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];
                                        ^
Comment 2 Martin Sebor 2018-05-08 02:48:53 UTC
This should be easily fixable for the simple cases involving string constants.  It may not be so simple for the non-constant ones.
Comment 3 Martin Sebor 2018-05-10 19:27:11 UTC
Patch: https://gcc.gnu.org/ml/gcc-patches/2018-05/msg00509.html
Comment 4 Martin Sebor 2018-05-22 17:46:27 UTC
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
Comment 5 Martin Sebor 2018-05-22 17:46:47 UTC
Patch committed to trunk in r260541.
Comment 6 Martin Sebor 2018-06-04 15:36:21 UTC
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
Comment 7 Martin Sebor 2018-06-04 15:37:28 UTC
Patch backported into 8-branch in r261152.