依据 Linux 内核邮件列表的音讯,社区近日探讨了是否要为内核采纳古代 C 语言规范。
尽管 Linux 内核在疾速倒退,但它同时依赖着一些十分古老的工具,其中之一就是内核代码仍在应用1989年版本的 C 语言规范——此规范在30多年前内核我的项目启动之前就曾经编写实现。从探讨后果来看,这一状况无望在5.18版本内核中扭转。

Jakob Koschel 在向 Linus Torvalds 递交的补丁(https://lkml.org/lkml/2022/2/...)中修复了内核链表相干的预测执行破绽。

Linux内核C语言将降级Linux内核C语言将降级

起因是 Jakob 发现了一个问题,Linux 内核宽泛应用由 struct list_head 定义的双向链表:

structlist_head{ structlist_headnext,prev;};
这种构造体通常被嵌入到其余构造体中,通过这种形式,开发者能够应用任何感兴趣的构造类型制作链表。除此之外,内核还提供了大量可用于遍历和操作链表的函数和宏。其中之一是 list_for_each_entry(),这是一个伪装成控制结构的宏。要理解如何应用此宏,请假如内核蕴含如下构造:

structfoo{intfooness;structlist_headlist;};
list 成员可用于创立 foo 构造体的双向链表,假如咱们有一个叫做 foo_list 的构造申明作为此类链表的头,应用以下代码能够遍历此列表:

struct foo *iterator;
list_for_each_entry(iterator, &foo_list, list) {
do_something_with(iterator);
}
/ Should not use iterator here /
list 参数通知宏在 foo 构造中 list_head 构造体的名称。此循环将为列表中的每个元素执行一次,迭代器指向该元素。由此导致了 USB 子系统中的一个 bug:传递给该宏的迭代器在退出宏后还能被应用。

Koschel 通过从新编写有问题的代码,以在循环后停止使用迭代器来解决问题。

不过 Linus 却对补丁修复的问题示意不解,也没有看到它与预测执行破绽的关系。Koschel 对此进行了进一步解释,对此 Linus 认为这只是一个一般的 bug。但不久之后 Linus 发现了问题的本源所在:传递给列表遍历宏的迭代器,必须在循环自身之外的范畴内申明。

随后,Linus 认为兴许能够采纳更间接的修复如块级变量申明。但 C89不反对,而1999年公布的 C99规范反对。所以 Linux 内核兴许是时候转向应用 C99规范了。

Linus 说到,内核代码始终停留在 C89的起因之一是编译器 gcc 的旧版本会呈现奇怪的问题,导致初始化程序被毁坏。不过当初内核要求的 GCC 最低版本曾经进步到了 v5.1,那些 bug 可能不再相干了。

另一位亲密关注架构编译器问题的内核开发者 Arnd Bergmann 提议间接降级到 C11甚至 C2x,只管他不确定 C11是否会带来任何对内核有用的新内容。不过如果降级到 C17或 C2x,会毁坏对 gcc-5/6/7的反对,因而降级到 C11更容易实现,而且逾越太大内核社区未必承受。

Linus赞成了这个想法,在 Bergmann确认应该能够这样做之后,Linus发表将在下一个内核版本 v5.18中尝试应用 C11规范。如果一切顺利,下一个内核版本应用的 C 语言规范无望降级到 C11。