Linux之父终于被劝动:用了30年的Linux内核C语言将升级至C11
仍然使用89C语言的Linux内核终于要改变了。
今天,Linux开源社区宣布将在未来将内核C语言版本升级到C11。预计将在5.18版之后生效,即今年5月。
这个决定非常突然。从这个问题到官方声明只有一周的时间。你需要说服固执的Linux之父;Linus和Torvalds并不容易。
这件事的起因有一点偶然因素。
虫子的连锁反应
这个问题的根源来自上周的一次Linux社区讨论。
一位名叫JakobsongZuying的博士生在研究阻止与内核链表原语相关的预测执行漏洞时发现了这样一个问题。
Linux内核被head定义的structlistuu双向链表广泛使用:
这种结构通常嵌入其他结构中。通过这种方式,您可以使用任何相关的结构类型创建一个链表。
此外,内核还提供了大量可用于遍历和操作链表的函数和宏。list_ufor_u每个_u条目()都是其中之一,它是一个伪装成控件结构的宏。
问题在于这个宏。
假设内核包含以下结构:
列表中的元素可用于创建foo结构的双向链接列表。
假设有一个叫做foo_u的链表,链表的结构声明就是这种链表的开头。您可以使用以下代码遍历此链表:
list参数告诉宏在foo结构中列出head结构的名称。对于迭代器指向的列表中的每个元素,该循环将执行一次。
这导致了USB子系统中的一个错误:在退出宏后后,传递给宏的迭代器仍然可以使用。
这是一件危险的事情,所以Koschel提交了一个补丁,在循环后停止使用迭代器,并修复了错误。
说服Linus
然而,Linus和Torvalds不太喜欢这个补丁,他们也没有看到它与预测的执行漏洞之间的关系。在Koschel详细解释后,Linus承认这只是一个普通的bug。
然而,事情并没有那么简单。Linus很快意识到了真正的根本原因:
传递给链表遍历宏的迭代器必须在循环本身的范围之外声明。
出现这种非预测性错误是因为C89不“在循环中声明变量”。
像list_ufor_uu每个uu宏,比如entry(),基本上总是将最后一个head条目泄漏出循环,只是因为我们不能在循环本身中声明迭代器变量。
如果您可以编写一个遍历宏来声明自己的迭代器列表,那么迭代器在循环外就不可见,这样的问题就不会发生。
然而,由于内核保持在C89标准上,变量不能在循环中声明。
Linus决定我们最好升级。也许是时候转向C99标准了。
尽管它已有20多年的历史,但它至少比C89更新,可以在循环中声明变量。
C89这么老了,这么多年没变吗?Linus说,这是因为我们在一些古老的gcc编译器版本中遇到了一些奇怪的问题,不能随意升级。
然而,现在Linux内核已经将GCC的最低要求升级到5.1版,过去应该没有奇怪的错误。
另一位核心开发者ArndBergmann认为,我们可以升级到C11或更高版本。然而,升级到C17或c2x将破坏对gcc-5/6/7的支持,因此升级到C11更容易。
最后,Torvalds同意了这个想法:“好的,请提醒我,让我们在5.18合并窗口的早期尝试一下。”
接下来,迁移到C11可能会导致一些意想不到的错误,但如果一切顺利,Linus的下一个版本的内核将正式转向C11。
参考链接:
[1]https://lwn.net/SubscriberLink/885941/01fdc39df2ecc25f/
[2]https://news.ycombinator.com/item?id=30459634
© 本文系原创,著作权归:芦虎导航官网。如需转载,请署名并注明出处:https://www.luhu.co/article/000000000015606.shtml



















