晓查 发自 凹非寺
量子位 | 大众号 QbitAI
还在应用89年版C言语的Linux内核,当初终于要做出转变了。
明天,Linux开源社区发布,将来会把内核C言语版本进级到C11,估计5.18版之后失效,也就是往年5月。
这个决议很忽然,从发动成绩到官方申明,不外才一个礼拜,要晓得压服执拗的Linux之父Linus Torvalds可不是件轻易的事。
事件的起因,提及来另有那么一点偶尔的要素。
一个bug的连锁反映
成绩的来源是来自上周的一次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构造的双向链表。
假设有一个叫做 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提交了一个修复补丁,在轮回后结束应用迭代器搞定了bug。
压服Linus
然而Linus Torvalds自己并不太爱好这个补丁,也不看到它与猜测履行破绽的关联。在Koschel具体说明后,Linus否认这只是一个一般的bug。
但是事件并不那么简略,Linus未几后认识到了真正的本源:
通报给链表遍历宏的迭代器,必需在轮回自身之外的范畴内申明。
这种非猜测性bug产生的起因是,C89中不“在轮回中申明变量”。
像list_for_each_entry()如许的宏,从基本上老是将最后一个HEAD进口泄露到轮回之外,仅仅是由于咱们不克不及在轮回自身中申明迭代器变量。
假如能够编写一个能够申明本人的迭代器列表遍历宏,那么迭代器在轮回之外将弗成见,而且不会呈现此类成绩。
然而,因为内核停顿在C89尺度上,因而无奈在轮回中申明变量。
Linus决议,那我们仍是进级吧,兴许是时间转向C99尺度了。
固然它也有20多年的汗青,但至少比C89新,能够在轮回中申明变量。
既然C89如斯陈腐,这么多年还没做出转变呢?Linus说,那是由于咱们在一些陈旧的gcc编译器版本中碰到了一些奇异的成绩,不克不及随意进级。
然而,当初Linux内核已将gcc的最低请求晋升至5.1版,因而从前那些奇异的bug应当不会有了。
而另一位中心开辟者Arnd Bergmann以为,我们完整能够进级到C11乃至更高版本。但假如进级到C17或C2x,会损坏对gcc-5/6/7的支撑,因而进级到C11更轻易实现。
终极,Torvalds同意这个主意:“好的,请提示我,让咱们在5.18兼并窗口的晚期实验一下。”
接上去迁徙到C11可能会招致一些意想不到的bug,但假如所有顺遂,下一个Linus内核版本将正式转向C11。
参考链接:
[1]https://lwn.net/SubscriberLink/885941/01fdc39df2ecc25f/
[2]https://news.ycombinator.com/item?id=30459634