最近傳來消息,令人振奮的是,一直以來使用的1989年版C語言的Linux核心終於迎來了一次重大的升級。當代科技的腳步不可阻擋,今天,Linux開源社群宣布了一個引人注目的計劃,即將將核心的C語言版本提升至C11標準。根據預計,這項重大的改革將於Linux 5.18版本之後生效,也就是即將到來的五月。這項重要措施將為Linux核心帶來潛力無限的機遇,並促進其更好地適應現代化技術的需求。
這個決定很突然,從發起問題到官方聲明,不過才一個星期,要知道說服固執的 Linux 之父 Linus Torvalds 可不是件容易的事。事情的原因,說起來還有那麼一點偶然的因素。
問題的起源是來自上週的一次 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 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,但如果一切順利,下一個Linux 核心版本將正式轉向C11。
以上是Linux 之父終於被說服:用了 30 年的 Linux 核心 C 語言將升級至 C11的詳細內容。更多資訊請關注PHP中文網其他相關文章!