简体   繁体   中英

GCC false positive warning on strncpy usage?

Yet another question regarding strncpy warning.

Here's the code:

#include <cstring>

extern char g_dest[16];
extern char g_src[16];

char* mycopy()
{
    char * x = strncpy ( g_dest, g_src, sizeof ( g_dest ) - 1 );
    return x;
}

Compile it with g++ version 8.3:

$ g++ --version
g++ (GCC) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ -Wall -Wextra -Werror -O3 -c strncpy-warning2.cxx
strncpy-warning2.cxx: In function ‘char* mycopy()’:
strncpy-warning2.cxx:8:24: error: ‘char* strncpy(char*, const char*, size_t)’ output may be truncated copying 15 bytes from a string of length 15 [-Werror=stringop-truncation]
     char * x = strncpy ( g_dest, g_src, sizeof ( g_dest ) - 1 );
                ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus: all warnings being treated as errors

The warning can be worked around by either:

  1. making the g_src shorter than g_dest:
$ cat strncpy-warning2.cxx
#include <cstring>

extern char g_dest[16];
extern char g_src[15];

char* mycopy()
{
    char * x = strncpy ( g_dest, g_src, sizeof ( g_dest ) - 1 );
    return x;
}
$ g++ -Wall -Wextra -Werror -O3 -c strncpy-warning2.cxx
$
  1. Or explicitly adding a NUL terminator at the end of g_dest :
$ cat strncpy-warning2.cxx
#include <cstring>

extern char g_dest[16];
extern char g_src[16];

char* mycopy()
{
    char * x = strncpy ( g_dest, g_src, sizeof ( g_dest ) - 1 );
    g_dest[ sizeof( g_dest ) - 1 ] = '\0';
    return x;
}
$ g++ -Wall -Wextra -Werror -O3 -c strncpy-warning2.cxx
$
  1. Or if I make the g_src a pointer instead of an array:
$ cat strncpy-warning2.cxx
#include <cstring>

extern char g_dest[16];
extern char* g_src2;

char* mycopy()
{
    char * x = strncpy ( g_dest, g_src2, sizeof ( g_dest ) - 1 );
    return x;
}
$ g++ -Wall -Wextra -Werror -O3 -c strncpy-warning2.cxx
$

I understand that GCC is trying to warn against potential bugs on strncpy usage, however, I don't understand why we cannot do strncpy on 2 arrays of the same size? And why the warning message is saying the output maybe truncated ? ( ie I cannot find an example that the output can possibly be truncated unless GCC assumes g_src may not necessarily a valid NUL-terminated c-string. )

By googling, I see a similar case reported in GCC bugzilla: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87028 , however, I'm not sure if that is the same case since that is marked as FIXED in the end but apparently my issue is still there in GCC 10.2.

Thank you!

The best (most efficient, simplest, easiest to understand for both success and error cases) is to use memcpy when your source and destination are the same fairly small size. GCC won't warn you about that.

If you simply want GCC to not complain about your strncpy() call even if it is unsafe, you can enclose it in parentheses like this:

char * x = (strncpy ( g_dest, g_src, sizeof ( g_dest ) - 1 ));

GCC understands this to mean "I know what I'm doing, don't try to save me from myself."

The length passed to strncpy is the maximum number of bytes to copy, including a possible null terminator, not the “string length” that excludes the null terminator. Use sizeof g_dest , not sizeof ( g_dest ) - 1 .

If g_src contains a string of 15 non-null characters and a null terminator, then strncpy(g_dest, g_src, sizeof g_dest - 1); will not copy it; it will copy only 15 characters and not copy the null terminator. Nor will it append a null terminator that is not already present and copied within the length (although it will append nulls up to the given length).

This is what the compiler is warning you about. strncpy should be passed the full length of the buffer, not the “string length.”

In a case like this, I would rather use strcpy() . I tried to run strncpy() multiple times on other projects and I think that it is protected by the compiler due to cases when you create a string by for-loop without the '\0' operator. Maybe I am wrong but this reason was sufficient enough for me at that time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM