https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85623

            Bug ID: 85623
           Summary: strncmp() warns about attribute 'nonstring'
                    incorrectly in -Wstringop-overflow
           Product: gcc
           Version: 8.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: gandalf at winds dot org
  Target Milestone: ---

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.

Reply via email to