【问题标题】:Why does GCC 9.1.0 sometimes complain about this use of strncpy()?为什么 GCC 9.1.0 有时会抱怨这种 strncpy() 的使用?
【发布时间】:2019-05-22 09:48:52
【问题描述】:

这是一个 40 行的 MCVE (Minimal, Complete, Verifiable Example) - 或接近最小的东西 - 从一个 1675 行的源文件中删减,该文件最初包含 32 个标头(其中大多数包含多个其他标头 - 使用 @987654324 编译它@ 列出了来自项目和系统的 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 编译时,我没有收到任何错误报告。

问题

一个问题的两个方面:

  • 为什么在使用-USUPPRESS_BUG 编译代码时,GCC 9.1.0 报错使用strncpy()
  • 为什么用-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 代码,只是在“真实代码”中,bug 没有被抑制。

【问题讨论】:

  • 在测试代码中,将strncpy() 调用更改为使用SERVERNAME_LEN + 1sizeof(name) 会删除警告。可悲的是,在“真实代码”中,都没有删除警告(但错误更改为 error: ‘__builtin_strncpy’ specified bound 129 equals destination size [-Werror=stringop-truncation] 并指向第二个 strncpy() 而不是第一个。我可能会在今天晚些时候将其整合到问题中。跨度>
  • 顺便说一句:即使 gcc 8.1 也抱怨:godbolt.org/z/YyFJcL。 7.3 和更早版本不要。
  • @Jabberwocky:有趣——对我来说,GCC 7.3.0、8.2.0 和 8.3.0 都没有抱怨使用-USUPPRESS_BUG(或没有任何@987654348 定义)编译时显示的测试代码@)。他们同样对“真正的代码”保持沉默。这些都是我构建的编译器——使用我在 SO 上其他地方记录的配方(Install GNU GCC on Mac——我在 Linux 上也使用基本相同的配方)。
  • 我有一个问题:在处理此消息的哪个阶段生成?当代码在 RTL 中时? SSA ?通用?

标签: c gcc


【解决方案1】:

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

GCC 附带此已知错误,因为它不被视为发布关键。

说实话,我不是 100% 确定这是 错误。关键是,存在已知的误报。如果您想帮助 GCC 项目,您可以在 strncpy / Wstringop-truncation 错误中找到最合适的错误并将您的示例发布在那里。如果您进一步最小化它会更有帮助(例如,使用creduce);最小化编译字符串也是值得赞赏的(我猜这将是相当微不足道的)。

【讨论】:

    【解决方案2】:

    在 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 不是稳定版本。希望当这些版本稳定后它们会被淘汰。

    【讨论】:

    • GCC 9.1.0 于 2019-05-03 发布。我使用的是发布代码,而不是发布前的最新版本。但有趣的是,其他人注意到似乎是同样的问题并抱怨并对此一无所知。
    • 我有一个问题:在处理此消息的哪个阶段生成?当代码在 RTL 中时? SSA ?通用?
    猜你喜欢
    • 2013-07-02
    • 2016-02-27
    • 1970-01-01
    • 1970-01-01
    • 2017-01-17
    • 1970-01-01
    • 1970-01-01
    • 2016-10-30
    • 1970-01-01
    相关资源
    最近更新 更多