Why “-flto” silent GCC’s warning “stringop-truncation”

I understand that newer GCC versions introduced a warning for possibly wrong string operations “stringop-truncation”

And here’s the sample code that I can easily trigger this warning:

$ cat strncpy-warning.cxx
#include <cstring>

extern char g_buf[16];

void mycopy ( const char* src_c_str )
{
    strncpy ( g_buf, src_c_str, sizeof ( g_buf ) );
}

Compile it with the following flags triggers this warning:

$ 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 -std=c++14 -Wextra -Werror -O3 -c strncpy-warning.cxx
strncpy-warning.cxx: In function ‘void mycopy(const char*)’:
strncpy-warning.cxx:7:13: error: ‘char* strncpy(char*, const char*, size_t)’ specified bound 16 equals destination size [-Werror=stringop-truncation]
     strncpy ( g_buf, src_c_str, sizeof ( g_buf ) );
     ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus: all warnings being treated as errors

Which is expected, however, if I added an -flto to the flags, this warning is gone and the object file is generated:

$ g++ -Wall -std=c++14 -Wextra -Werror -O3 -c strncpy-warning.cxx -flto
$ ls strncpy-warning.o
strncpy-warning.o

Apparently, -flto WILL catch some compile time warnings so not sure why that stringop-truncation is not caught, e.g.:

$ cat strncpy-warning.cxx
#include <cstring>

extern char g_buf[16];

void mycopy ( const char* src_c_str, const char* unused )
{
    strncpy ( g_buf, src_c_str, sizeof ( g_buf ) );
}

$ g++ -Wall -std=c++14 -Wextra -Werror -O3 -c strncpy-warning.cxx -flto
strncpy-warning.cxx: In function ‘void mycopy(const char*, const char*)’:
strncpy-warning.cxx:5:50: error: unused parameter ‘unused’ [-Werror=unused-parameter]
 void mycopy ( const char* src_c_str, const char* unused )
                                      ~~~~~~~~~~~~^~~~~~
cc1plus: all warnings being treated as errors                                               

So the question is:

  1. Is this expected behavior?
  2. I understand that with -flto specified for a source file, GCC will write special things into the resulting object file ( *.o ), but the question is why the warning is skipped by GCC? Is that intentional?
  3. Is there a way to enable this warning even in case of -flto is given?
  4. Or does the point-3 above make any sense?

Many thanks!

Answer

Roughly speaking, GCC has two kinds of warnings:

  • Warnings generated by simple analysis of the source code
  • Warnings generated by complex analysis of data flow

An unused parameter is the first kind: it’s trivial to see that a parameter is simply not used in a function.

Incorrect usage of strncpy is, except for trivial cases, the second kind: the compiler needs to understand the relationship between the first and third arguments to strncpy, it needs to know the actual (or at least symbolic) value passed in the third argument, and it needs to know the actual (or at least symbolic) size available in the first argument.

The first kind of warning is generated by the frontend parser. Thus, it always fires.

The second kind is generated by the same component that optimizes the code, because only this component has the necessary information. In -flto mode, this component doesn’t run for individual source files.

The second kind also sometimes depends on specific optimizations being performed at all: if you change the optimization level in your first command line to -O1, the warning isn’t emitted either.