终于升级?89年的Linux内核C语言“跟上时代”转成现代C

百家 作者:CSDN 2022-03-01 17:35:46

整理 | 章雨铭       责编 | 屠敏
出品 | CSDN(ID:CSDNnews)

上周《LINUX设备驱动程序第三版》的第一作者、LWN网络杂志创始人兼主编Jonathan Corbet发表了对于Linux内核的一些看法,他认为虽然内核项目总体发展快速,但内核代码仍然使用1989年版本的C语言标准,而5.18内核可能会结束这种情况。

是的,没错,拥有30年历史的Linux内核C语言要升级了。Linux开源社区已经宣布,2022年五月将把内核C语言版本升级到C11。


源于一次补丁,Linux内核缺陷显现


这一决定很迅速,从问题发起到官方拍板宣布用时短短一周。

这一提案要从 Linux 内核贡献者Jakob Koschel的补丁系列说起。

他在研究阻止与内核链表primitive相关的预测执行漏洞时,发现了这样一个问题。Linux内核中大量使用了由struct list_head定义的双链表。

 struct list_head {  struct list_head *next, *prev;    };

这种结构通常被嵌入到一些其他结构中。通过这种方式,让任何相关的结构类型都能创建链表。随着类型的出现,内核提供了大量可以用来遍历和操作链表的函数和宏。其中之一是list_for_each_entry(),它是一个伪装成控制结构的宏。为了了解这个宏的使用方法,内核中包括以下结构:

struct foo {      int fooness;  struct list_head list;    };

list中的元素可以用来创建一个由foo结构组成的双链列表;一个单独的list_head结构通常被视为这个列表的开头,假设有一个叫做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子系统中会出现错误,传递给这个宏的迭代器在退出宏后仍可以使用,这是件非常危险的事。Koschel提交补丁,修复了这个错误。根据列表中发生的情况,该迭代器的内容可能出人意料,即使在没有预测执行的情况下。Koschel重写了相关代码,循环后不再需要通过迭代器解决问题。


Linus拍板:Linux内核C语言将升级为C11


事实上,Linux内核的发明人及该计划的合作者Linus Torvalds开始对于这一补丁并不感冒,也不理解它和预测执行漏洞的关系。

不过,在Koschel进一步解释情况后,Torvalds认同"这只是一个常规的错误,简单明了"。但随后他又谈到了问题的真正根源:传递给列表遍历宏的迭代器必须在循环本身之外的范围内声明。

这种非投机性错误之所以会发生,是因为我们在历史上没有C99风格的"在循环中声明变量"。所以list_for_each_entry()——以及所有其他的——往往会将最后一个HEAD条目从循环中泄露出来,仅仅是因为我们无法在循环本身中声明迭代器变量。

如果有可能编写一个可以声明自己的迭代器的列表遍历宏,那么这个迭代器在循环之外是不可见的,就不会出现这种问题。但是,由于内核停留在C89标准上,在循环中声明变量是不可能的。

Torvalds说,也许现在已经到了考虑转向C99标准的时候了——虽然它已经有了20多年的历史,但依旧是最新的版本,足以允许块级变量声明。正如他所指出的,之所以过去没有这样做,"因为我们在一些古老的gcc版本中遇到了一些问题,破坏了文件的初始化器"。但是,与此同时,内核已经把它的最低GCC要求移到了5.1版本,所以也许那些错误已经不重要了。

Linux内核的开发者Arnd Bergmann也非常赞同这一观点,他认为内核有向前发展的可能。事实上,他建议,在进行改变的同时,有可能达到C11标准(从2011年开始),尽管他不确定C11是否会带来对内核有用的新东西。甚至有可能转移到C17甚至尚未完成的C2x版本的语言。然而,这同样存在一个问题,那就是"会破坏对gcc-5/6/7的支持",而目前内核仍然支持这些版本。将GCC的最低版本提高到8.x,可能会和用户社区目前愿意接受的版本有很大的差距。

不过,转移到C11将不需要改变GCC的最低版本,因此可能更容易做到。Torvalds对这个想法表示赞同,并且希望最终能够取得成果。在Bergmann确认这可行之后,Torvalds宣布在5.18合并窗口进行早期尝试。

值得注意的是,在合并窗口和5.18版本之间可能发生很多事情。迁移到新版本的语言标准,可能导致内核中一些不明显的地方出现小bug,而往往一个小小的bug就有可能导致现在的改变被撤销。但是,如果一切顺利的话,下一个内核版本就可能会被正式迁移到C11上。将list_for_each_entry()的所有用户和变种(在内核中有超过15,000个)转换为不暴露内部迭代器的新版本,不过这可能要花不少时间。

你对这次升级有什么看法呢,你觉得升级后会带来什么改变?欢迎大家在下方留言!

 

参考资料:https://lwn.net/SubscriberLink/885941/01fdc39df2ecc25f/

END

 

《新程序员001-004》全面上市,对话世界级大师,报道中国IT行业创新创造



— 推荐阅读 —
曝华为新成立10大预备军团;被罚2500万欧元,苹果开放第三方支付;GitLab 14.8发布 | 极客头条
那个名为 XROS 的操作系统,倒在了元宇宙浪潮中!
☞“兼职开发的程序员,为什么不受企业待见?”

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接