7

This is a 40-line MCVE (Minimal, Complete, Verifiable Example) — or something close to minimal — cut down from a 1675 line source file that originally included 32 headers (and most of those included multiple other headers — compiling it with gcc -H lists 464 headers from the project and the system, many of them several times). That file is working code that previously compiled without warnings (GCC 8.3.0), but not with GCC 9.1.0. All structure, function, type, variable names have been changed.

pf31.c

#include <string.h>

enum { SERVERNAME_LEN = 128 };

typedef struct ServerQueue
{
    char server_name[SERVERNAME_LEN + 1];
    struct ServerQueue *next;
} ServerQueue;

extern int function_under_test(char *servername);

#ifdef SUPPRESS_BUG
extern int function_using_name(char *name);
#endif /* SUPPRESS_BUG */

extern int GetServerQueue(const char *servername, ServerQueue *queue);

int
function_under_test(char *servername)
{
    ServerQueue queue;
    char name[SERVERNAME_LEN + 1];

    if (GetServerQueue(servername, &queue) != 0)
        return -1;
    char *name_in_queue = queue.server_name;

    if (name_in_queue)
        strncpy(name, name_in_queue, SERVERNAME_LEN);
    else
        strncpy(name, servername, SERVERNAME_LEN);
    name[SERVERNAME_LEN] = '\0';

#ifdef SUPPRESS_BUG
    return function_using_name(name);
#else
    return 0;
#endif /* SUPPRESS_BUG */
}

Compilation

When compiled using GCC 9.1.0 (on a Mac running macOS 10.14.5 Mojave, or on a Linux VM running RedHat 5.x — don't ask!), with the option -DSUPPRESS_BUG I get no error, but with the option -USUPPRESS_BUG, I get an error:

$ gcc -std=c11 -O3 -g -Wall -Wextra -Werror -DSUPPRESS_BUG  -c pf31.c
$ gcc -std=c11 -O3 -g -Wall -Wextra -Werror -USUPPRESS_BUG  -c pf31.c
In file included from /usr/include/string.h:417,
                 from pf31.c:1:
pf31.c: In function ‘function_under_test’:
pf31.c:30:9: error: ‘__builtin_strncpy’ output may be truncated copying 128 bytes from a string of length 128 [-Werror=stringop-truncation]
   30 |         strncpy(name, name_in_queue, SERVERNAME_LEN);
      |         ^~~~~~~
cc1: all warnings being treated as errors
$

When I compile using GCC 8.3.0, I get no errors reported.

Question

Two sides of one question:

  • Why does GCC 9.1.0 complain about the use of strncpy() when the code is compiled with -USUPPRESS_BUG?
  • Why doesn't it complain when the code is compiled with -DSUPPRESS_BUG?
    • Corollary: is there a way to work around this unwanted warning that works with older GCC versions as well as 9.1.0. I've not yet found one. There's also a strong element of "I don't think it should be necessary, because this is using strncpy() to limit the amount of data copied, which is what it is designed for".

Another variant

I have another non-erroring variant, changing the signature of the function_under_test() — here's a set of diffs:

11c11
< extern int function_under_test(char *servername);
---
> extern int function_under_test(char *servername, ServerQueue *queue);
20c20
< function_under_test(char *servername)
---
> function_under_test(char *servername, ServerQueue *queue)
22d21
<     ServerQueue queue;
25c24
<     if (GetServerQueue(servername, &queue) != 0)
---
>     if (GetServerQueue(servername, queue) != 0)
27c26
<     char *name_in_queue = queue.server_name;
---
>     char *name_in_queue = queue->server_name;

This compiles cleanly regardless of whether SUPPRESS_BUG is defined or not.

As you can guess from the SUPPRESS_BUG terminology, I'm tending towards the view that this is bug in GCC, but I'm kinda cautious about claiming it is one just yet.


More about the the original code: the function itself was 540 lines long; the strncpy() block occurs about 170 lines into the function; the variable corresponding to name was used further down the function in a number of function call, some of which take name as an argument and supply a return value for the function. This corresponds more to the -DSUPPRESS_BUG code, except that in the 'real code', the bug is not suppressed.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • In the test code, changing the `strncpy()` calls to use either `SERVERNAME_LEN + 1` or `sizeof(name)` removes the warning. Sadly, in the 'real code', neither removes the warning (but the error changes to `error: ‘__builtin_strncpy’ specified bound 129 equals destination size [-Werror=stringop-truncation]` and points to the second `strncpy()` instead of the first. I'll integrate this into the question later today, probably. – Jonathan Leffler May 22 '19 at 10:12
  • BTW: even gcc 8.1 complains: https://www.godbolt.org/z/YyFJcL. 7.3 and older don't. – Jabberwocky May 22 '19 at 10:28
  • @Jabberwocky: Interesting — for me, none of GCC 7.3.0, 8.2.0 and 8.3.0 complain about the test code shown when compiled with `-USUPPRESS_BUG` (or without any definition of `SUPPRESS_BUG`). And they are similarly quiet about the 'real code'. These are all compilers I built — using a recipe I've documented elsewhere on SO ([Install GNU GCC on Mac](https://stackoverflow.com/questions/21173518/install-gnu-gcc-on-mac/21213759#21213759) — I use basically the same recipe on Linux too). – Jonathan Leffler May 22 '19 at 10:44
  • I have a question: at which stage in processing this message is generated ? When the code is in RTL ? SSA ? Generic ? – alinsoar May 22 '19 at 13:15

2 Answers2

4

This is a GCC bug tracked as PR88780. According to Martin's comment, this warning did not exist prior to GCC 8.

GCC is shipped with this known bug, as it is not deemed release-critical.

To be honest, I am not 100% sure it is the bug. The point is, there are known false-positives. If you feel like helping the GCC project, you can find the most appropriate bug among strncpy / Wstringop-truncation bugs and post your example there. It would be more helpful if you minimized it further (say, with creduce); minimizing the compile string is also appreciated (that would be rather trivial, I guess).

Vladislav Ivanishin
  • 2,092
  • 16
  • 22
2

Several compilation warnings related to strncpy were found in GCC 9.0 and reported here and here.

One of them is the error mentioned in the question which seems to occur in the file string_fortified.h:

/usr/include/bits/string_fortified.h:106:10: warning: ‘__builtin_strncpy’ output may be truncated copying 16 bytes from a string of length 16 [-Wstringop-truncation]
  106 |   return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The response to this was given on April 15, 2019 was:

Thank you for the report, however as GCC 9 still under development. We do not see the above errors in the current stable GCC 7.4 or GCC 8.3. We appreciate the advanced notice, and will accept PRs to fix issues against GCC 9, but for now our target compiler is gcc stable.

So I believe the errors are probably a result of versions 9 and 9.1 being not stable versions. Hopefully they will be eliminated when these versions become stable.

P.W
  • 26,289
  • 6
  • 39
  • 76
  • 1
    GCC 9.1.0 was released on 2019-05-03. I'm using release code, not a bleeding edge build before release. But it is interesting that someone else has noticed what seems to be the same problem and complained and got stone-walled about it. – Jonathan Leffler May 22 '19 at 10:36
  • I have a question: at which stage in processing this message is generated ? When the code is in RTL ? SSA ? Generic ? – alinsoar May 22 '19 at 13:24