为什么GCC 9.1.0有时会抱怨使用strncpy()?

时间:2019-05-22 09:48:53

标签: c gcc

这是一个40行的MCVE(Minimal, Complete, Verifiable Example)-或接近最低限度-从1675行源文件中删除,该文件最初包含32个标头(其中大多数包含多个其他标头,请使用gcc -H列出了项目和系统中的464个标头,其中许多标头多次。该文件是以前没有警告(GCC 8.3.0)但没有GCC 9.1.0编译的工作代码。所有结构,功能,类型,变量名称均已更改。

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 */
}

编译

使用GCC 9.1.0进行编译时(在运行macOS 10.14.5 Mojave的Mac上,或在运行RedHat 5.x的Linux VM上-不用问!),使用选项-DSUPPRESS_BUG,我不会错误,但使用选项-USUPPRESS_BUG,我得到一个错误:

$ 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
$

当我使用GCC 8.3.0进行编译时,没有错误报告。

问题

一个问题的两个侧面:

  • 当用strncpy()编译代码时,为什么GCC 9.1.0会抱怨使用-USUPPRESS_BUG
  • 为什么用-DSUPPRESS_BUG编译代码时不会抱怨?
    • 推论:有没有办法解决这种不必要的警告,该警告适用于较旧的GCC版本和9.1.0。我还没有找到。还有一个很强的要素:“我认为没有必要,因为它使用strncpy()来限制复制的数据量,这正是它的设计目的。”

另一个变体

我还有另一个不错的变体,更改了function_under_test()的签名-这是一组差异:

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;

无论是否定义了SUPPRESS_BUG,它都会干净地编译。

您可以从SUPPRESS_BUG术语中猜到,我倾向于认为这是GCC中的错误,但对于声称它只是一个错误,我有些谨慎。


有关原始代码的更多信息:函数本身长540行; strncpy()块出现在函数中约170行;对应于name的变量在许多函数调用中被进一步使用,其中一些函数以name作为参数,并为函数提供返回值。这更类似于-DSUPPRESS_BUG代码,除了在“真实代码”中,该错误没有被抑制。

2 个答案:

答案 0 :(得分:3)

在GCC 9.0中发现了与strncpy相关的几个编译警告,并报告了herehere

其中之一是问题中提到的错误,该错误似乎发生在文件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));
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

对此的答复是在2019年4月15日给出的:

  

感谢您的报告,但是GCC 9仍在开发中。在当前稳定的GCC 7.4或GCC 8.3中,我们看不到上述错误。我们非常感谢您提前通知,并且会接受PR来解决针对GCC 9的问题,但目前我们的目标编译器是gcc稳定的。

因此,我认为这些错误可能是由于版本9和9.1不是稳定版本造成的。希望这些版本稳定后将被淘汰。

答案 1 :(得分:3)

这是一个GCC错误,跟踪为PR88780。根据Martin comment的说法,此警告在GCC 8之前不存在。

GCC带有此已知错误,因为它不认为是关键发布。

说实话,我不确定100%是 the 错误。关键是,存在已知的假阳性。如果您想帮助GCC项目,则可以在strncpy / Wstringop-truncation个bug中找到最合适的bug,然后在其中发布示例。如果进一步将其最小化(例如,使用creduce),则将更有用。最小化编译字符串也受到赞赏(我想那是微不足道的)。