c - 为什么 GCC 9.1.0 有时会抱怨这种 strncpy() 的使用?
问题描述
这是一个 40 行的 MCVE(最小、完整、可验证的示例)——或接近最小的东西——从最初包含 32 个标题的 1675 行源文件(其中大多数包含多个其他标题——用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
I get no error,但使用选项-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 编译时,我没有收到任何错误报告。
问题
一个问题的两个方面:
- 为什么 GCC 9.1.0 抱怨使用
strncpy()
when 编译代码-USUPPRESS_BUG
? - 为什么编译代码时它不抱怨
-DSUPPRESS_BUG
?- 推论:有没有办法解决这个不需要的警告,它适用于旧 GCC 版本以及 9.1.0。我还没有找到一个。还有一个强烈的元素“我认为没有必要,因为这是
strncpy()
用来限制复制的数据量,这是它的设计目的”。
- 推论:有没有办法解决这个不需要的警告,它适用于旧 GCC 版本以及 9.1.0。我还没有找到一个。还有一个强烈的元素“我认为没有必要,因为这是
另一种变体
我有另一个无错误的变体,改变了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
代码,除了在'真实代码'中,错误没有被抑制。
解决方案
这是一个跟踪为PR88780的 GCC 错误。根据 Martin 的评论,在 GCC 8 之前不存在此警告。
GCC 附带了这个已知的错误,因为它不是发布关键的。
老实说,我不是 100% 确定这是错误。关键是,存在已知的误报。如果您想帮助 GCC 项目,您可以在strncpy
/Wstringop-truncation
错误中找到最合适的错误并将您的示例发布到那里。如果您进一步将其最小化(例如,使用creduce
)会更有帮助;最小化编译字符串也很受欢迎(我猜这将是相当微不足道的)。
推荐阅读
- javascript - [开玩笑]:TypeError:对象原型可能只是一个对象或空:未定义
- rest - Microsoft Graph API - 从“公共文件夹”获取联系人/文件夹
- selenium - 保持浏览器在服务器/云上运行以跟踪实时数据的注意事项
- python - 解码和重新编码 TFRecord
- python - 对于目标总和问题,递归无法按预期工作
- c# - C#使用方法输出字符串列表
- ios - image_picker 颤动视频选择限制为 120 秒如何修复 IOS
- yaml - 公制路径不允许像 /? 输出=文本(普罗米修斯)
- networking - 为什么我们在 paramiko 中为 exec_command() 内置了重试?
- javascript - 接受一组特定道具的 react/jsx 元素的类型定义?