根据Linux内核邮件列表的消息,社区最近讨论是否采用现代C语言标准内核。Linus终于被说服了:30年的Linux内核C语言要升级了Linus终于被说服了:30年的Linux内核C语言要升级了旧工具,其中之一是内核代码仍然使用1989版的C语言标准——一个在内核项目开始之前30多年前编写的标准。从讨论的结果来看,这种情况有望在5.18内核中得到改变。JakobKoschel在LinusTorvalds(https://lkml.org/lkml/2022/2/…)的补丁中修复了一个与内核链表相关的推测执行漏洞。Linus终于被说服了:用了30年的Linux内核的C语言要升级了Linus终于被说服了:用了30年的Linux内核的C语言要升级了。原因是Jakob发现了一个问题,Linux内核被广泛使用。双向链表:structlist_head{structlist_headnext,prev;};这种结构通常嵌入在其他结构中,这样,开发人员可以使用任何感兴趣的结构类型来制作链表。此外,内核还提供了大量的函数和宏,可以用来遍历和操作链表。其中之一是list_for_each_entry(),这是一个伪装成控制结构的宏。要查看这个宏是如何使用的,假设内核包含以下结构:structfoo{intfooness;structlist_headlist;};list成员可以用来创建一个foo结构的双向链表,假设我们有一个名为foo_list的结构声明作为这个类的链表的头部,这个链表可以使用下面的代码遍历:structfoo*iterator;list_for_each_entry(iterator,&foo_list,list){do_something_with(iterator);}/这里不应该使用iterator/list参数告诉宏在foo结构体中以list_head结构体的名字。该循环将对迭代器指向的列表中的每个元素执行一次。这导致USB子系统中的一个错误:退出宏后可以使用传递给宏的迭代器。Koschel通过重写违规代码以在循环后停止使用迭代器解决了这个问题。然而,Linus对打补丁的问题一头雾水,并没有看出它与推测执行漏洞的关系。Koschel进一步解释了这一点,Linus认为这只是一个普通的错误。但没过多久Linus就发现了问题的根源:传递给列表遍历宏的迭代器必须在循环本身之外的范围内声明。后来,Linus认为也许可以采用更直接的修复方法,例如块级变量声明。但是C89不支持,1999年发布的C99标准支持。所以也许是时候让Linux内核转向C99标准了。Linus表示,内核代码一直卡在C89的原因之一是老版本的编译器gcc会出现奇怪的问题,导致initializer被破坏。但现在内核要求的最低GCC版本已经提升到v5.1,那些错误可能不再相关。另一位关注架构编译器问题的内核开发人员ArndBergmann建议直接升级到C11甚至C2x,尽管他不确定C11是否会给内核带来任何新东西。但是如果升级到C17或者C2x,会破坏对gcc-5/6/7的支持,所以升级到C11更容易实现,跨度太大内核社区可能不会接受。Linus接受了这个想法,在Bergmann确认应该可以这样做之后,Linus宣布他将在下一个内核版本v5.18中尝试使用C11标准。如果一切顺利,下一个内核版本使用的C语言标准有望升级为C11。
