LWN.net Logo LWN.net News from the source LWN

By Jonathan Corbet April 24, 2025

新的编译器版本通常会带来新的警告;这些警告通常是受欢迎的,因为它们可以帮助开发者在问题变成棘手的 bug 之前发现它们。然而,适应新的警告也会给开发过程带来混乱,特别是当一位重要的开发者在不恰当的时间升级到新的编译器时。这正是 6.15-rc3 kernel release 以及 GCC 15 中 -Wunterminated-string-initialization 的实现所发生的情况。

考虑一个 C 声明,例如:

  char foo[8] = "bar";

该数组将被给定的字符串初始化,包括表示字符串结尾的常规尾随 NUL 字节。现在考虑这个变体:

  char foo[8] = "NUL-free";

这是一个合法的声明,即使声明的数组现在缺少 NUL 字节的空间。该字节将被简单地省略,从而创建一个未终止的字符串。这通常不是编写该代码的开发者想要的,并且可能导致在稍后的某个时间才会被发现的令人不快的 bug。-Wunterminated-string-initialization 选项会为此类初始化发出警告,结果是,如果存在问题,问题有望得到快速修复。

内核社区一直在努力利用此警告,并希望消除 bug 的来源。但是,新警告只有一个小问题:有时,不使用 NUL 的初始化正是所需要和预期的。例如,请参见 fs/cachefiles/key.c 中的 此声明

  static const char cachefiles_charmap[64] =
	"0123456789"			/* 0 - 9 */
	"abcdefghijklmnopqrstuvwxyz"	/* 10 - 35 */
	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"	/* 36 - 61 */
	"_-"				/* 62 - 63 */
	;

char 数组用作查找表,而不是字符串,因此不需要尾随的 NUL 字节。 GCC 15 不知道这种用法,将为此声明发出误报警告。内核中有很多地方都有像这样的声明;例如,ACPI 代码使用大量的四字节字符串数组来处理同样大的四字母 ACPI 首字母缩略词集。

当然,有一种方法可以通过向声明添加一个属性来禁止不适用的警告,表明 char 数组实际上没有保存字符串:

  __attribute__((__nonstring__))

在内核中,宏 __nonstring 用于缩短该属性的语法。主要由 Kees Cook 进行的工作一直在进行中,以修复 GCC 15 添加的所有警告。已经分发了许多补丁;其中很多都在 linux-next 中。 Cook 还在与 GCC 开发者合作,以改进此注释的工作方式,并 修复内核项目遇到的问题。还有一些时间可以完成这项工作,因为 GCC 15 实际上尚未发布 - Cook 是这么认为的。

但是,Fedora 42 _已_发布,并且 Fedora 开发者(无论好坏)决定在其默认编译器中包含 GCC 15 的预发布版本。 Fedora 项目似乎已决定通过此版本遵循 一项历史悠久的 Red Hat 传统。 Linus Torvalds(无论好坏)决定在标记和发布 6.15-rc3 的前一天将其开发系统更新到 Fedora 42。但是,一旦他尝试使用新的编译器构建内核,事情就开始出错,因为相关的补丁尚未在他的存储库中。 Torvalds 以一系列他自己的更改做出回应,这些更改直接应用于主线,大约在发布前两个小时,以修复他遇到的问题。它们包括 此补丁 修复 ACPI 子系统中的警告,以及 此补丁 修复其他几个问题,包括上面显示的示例。然后,他标记并推出了包含这些更改的 6.15-rc3。

不幸的是,他的最后一刻的更改破坏了 GCC 15 预发布版本之前的任何 GCC 版本的构建 - 这个问题很可能会给任何没有运行 Fedora 42 的开发者带来一定程度的不便。因此,在 6.15-rc3 发布后不久,Torvalds 添加了 另一个补丁,该补丁撤消了破坏性更改并完全禁用了新警告。

这引起了 Cook 一条有些不满的评论,他说他已经发送了修复所有问题的补丁,包括 Torvalds 遇到的破坏构建的问题。他要求 Torvalds 恢复这些更改并使用计划的修复程序,并补充说:“当您更新到未发布的编译器版本时,这再次令人感到沮丧。” Torvalds 不同意,他说他需要进行更改,因为否则内核将无法构建。他还断言,GCC 15 _已_通过其在 Fedora 42 中的存在而发布。 Cook 没有留下深刻印象

是的,我理解,但是您没有与任何人协调。您没有在 lore 中搜索警告字符串,甚至没有检查 -next,您现在已经在其中创建了合并冲突。您在最后一刻将未经充分测试的补丁放入树中,并削减了一个对所有使用 GCC <15 的人来说都崩溃的 rc 版本。对于少得多的事情,您无情地抨击维护者。

Torvalds 坚持己见,但指责 Cook 没有足够快地将修复程序放入主线。

截至撰写本文时,情况就是这样。毫无疑问,其他人会花时间正确地解决问题,并添加一直打算进行的更改。但是,这一系列事件在各方面都产生了一些不好的感觉,如果能更好地了解 GCC 的未来版本何时有望能够构建内核,也许可以避免这些感觉。

作为一种尾声,值得一提的是,Torvalds 对此属性的实现方式也存在根本性的分歧。 __nonstring__ 属性适用于变量,而不适用于类型,因此必须在不带尾随 NUL 字节的 char 数组的每个位置使用它。他宁愿注释该类型,表明该类型的每个实例都保存字节而不是字符串,并避免标记相对较多的变量声明的需求。但这并不是该属性的工作方式,因此内核必须为以这种方式使用的每个 char 数组包含 __nonstring 标记。