存在一種完美的編程語言嗎?
Rust 語言因其并發安全性而深受眾多開發者的喜愛,曾在多個榜單上獲評最受歡迎編程語言。然而,現在有人花費大量時間編寫 10 萬行 Rust 代碼之后,撰寫博客闡明 Rust 語言的一系列缺點,以下是博客的主要內容。 我深入研究 Rust 是為了改進由 Xobs 編寫的 Xous 操作系統。Xous 是一個用純 Rust 編寫的微內核消息傳遞操作系統,是為了輕量級 (IoT / 嵌入式規模) 的安全優先平臺(例如 Precursor)而編寫的,用于 MMU 的硬件強制型頁面級內存保護。
一年來,我們為 Xous 操作系統添加了許多功能,包括網絡 (TCP/UDP/DNS)、用于模態和多語言文本的中間件圖形抽象、存儲(以加密的形式)、PDDB、可信啟動(trusted boot)以及密鑰管理庫等。
我們決定編寫自己的操作系統而不是使用 SeL4、Tock、QNX 或 Linux 等現有實現,是因為我們想真正了設備中每一行代碼都在做什么。特別是對于 Linux,它的源代碼庫非常龐大且動態,即使開源,也不可能搞清其內核中的每一行代碼。
因此,Xous 僅支持我們的平臺,以盡可能避免內核不必要的復雜性。 這樣減少應用范圍還意味著我們還可以充分利用 CPU 在 FPGA 中運行的優勢 。因此,Xous 以一種不尋常的 RV32-IMAC 配置為目標:具有 MMU + AES 擴展的配置。 FPGA 意味著我們有能力在硬件級別上修復 API 錯誤,從而使內核更加精簡。
這對于從 RAM 中處理諸如掛起和恢復之類的抽象破壞(abstraction-busting)進程尤其重要。 我們創建 Xous 時研究了大量的系統編程語言,最終 Rust 脫穎而出。當時它剛剛開始支持 `no-std`,它的特點是強類型、內存安全,具有良好的工具和新型生態系統。我個人是強類型語言的忠實擁護者,而內存安全性不僅有利于系統編程,還能使優化器更好地生成代碼,并且 Rust 適用于并發。
實際上,我希望 Precursor 有一個支持標記指針和內存功能的 CPU,類似于 CHERI。于是我們和 CHERI 研發團隊進行了一些討論,但顯然他們非常專注于 C 語言,也沒有足夠的帶寬來支持 Rust。
總體而言,C 比 Rust 需要 CHERI 多得多,他們的選擇是符合資源優先原則的。我們不使用 C 語言,但出于安全性考慮,我希望有一天 Rust 中會存在硬件強制型胖指針(fat pointer)。
然而,Rust 語言絕不是完美的,甚至給我們的開發帶來了很多問題。下面我列舉一下 Rust 的缺點。
語法混亂復雜
我發現 Rust 語法密集、繁重且難以閱讀,例如:
再比如,Rust 宏的可讀性也存在問題——即使是我自己編寫的一些 Rust 宏也「只是勉強工作」。
一種可靠的語言不應該存在這些語法問題。 Rust 的確很強大,它的標準庫中包含 HashMaps、Vecs 和 Threads 等數據結構,豐富且可用性高。然而,Rust 的「std」庫并沒有為我們構建可審計的代碼庫帶來任何好處。
Rust 不夠完善
我們編寫 Xous 的代碼時,引入了一個叫作「const generic」的新類型。在此之前,Rust 沒有原生能力來處理多于 32 個元素的數組,這個限制令人抓狂。 在編寫 Xous 的過程中,Rust 的內聯匯編、工作空間等功能逐漸成熟,這意味著我們需要重新審視已經寫好的代碼,以使關鍵的初始啟動代碼集成進我們構建的系統。
Xous 開發的第一年都是使用’no-std’完成的,代價是占用大量內存空間且復雜性高。盡管可以編寫一個只有預先分配的、靜態大小的數據結構的操作系統,但為了適應最壞情況下的元素數量,因此我們不得不推出一些自己的數據結構。 大約一年前,Xobs 將 Rust 的 `std` 庫移植到 Xous,這意味著我們可以在穩定的 Rust 中訪問堆,現在 Xous 與特定版本的 Rust 綁定。 `std` 庫從根本上將內存分配、線程創建等「不安全」的硬件結構轉變成了「安全」的 Rust 結構。
然而,我必須不斷提醒自己,擁有 `std` 庫并不能消除關鍵代碼中的安全漏洞風險——它只是將許多關鍵代碼移動到標準庫中。 Rust 有固定的更新周期,這意味著我們也必須定期更新 Xous ,以保持與語言的兼容性。 但這可能是不可持續的。
最終,我們需要鎖定代碼庫,但我沒有明確的退出策略。也許我們可以考慮仍然使用 `no-std` 以獲得穩定的 `alloc` 功能來訪問堆。但這樣我們就還需要使用 Vec、HashMap、Thread 和 Arc/Mutex/Rc/RefCell/Box 構造等,以使 Xous 能夠被有效編碼。
Rust 在供應鏈安全方面堪憂
在 rustup.rs 安裝文件中有如下代碼:
Crates.io 也存在一種拼寫錯誤,很難確定哪些 crate 是好或壞;一些完全按照用戶想要的名稱命名的 crate 放棄提供所需功能,而積極維護的 crate 必須采用不太直觀的名稱。當然,這不是 Rust 獨有的問題。 還有一個事實是,依賴項是鏈式的。也就是說當你從 crates.io 拉入一個東西時,你也會拉入該 crate 的所有從屬依賴項,以及它們所有的 build.rs (http://build.rs/) 腳本,這些最終都將在你的機器上運行。
因此,僅審核 Cargo.toml 文件中明確指定的 crate 是不夠的——您還必須審核所有相關 crate 是否存在潛在的供應鏈攻擊。 幸運的是,Rust 確實允許您使用 Cargo.lock 文件將 crate 固定在特定版本,并且可以完全指定依賴 crate 。我們試圖在 Xous 中通過發布 Cargo.lock 文件并將我們所有的一階相關 crate 指定為次要修訂的策略來緩解這個問題。
然而,我們的大部分調試和測試框架都依賴于一些相當花哨和復雜的 crate,這些 crate 引入了大量的依賴項,即使我嘗試為我們的目標硬件運行構建,在主機上運行的依賴 crate 和 build.rs 腳本還是被構建。 針對這個問題,我編寫了一個名為「crate-scraper」的小工具,它為我們的 Cargo.toml 文件中指定的每個源下載源包,并且將它們存儲在本地,這樣我們就可以獲得用于構建 Xous 版本的代碼快照。
它還運行一個快速的「分析」程序——搜索名為 build.rs 的文件并將它們整理到一個文件中,這樣我就可以更快地通過 grep 查找明顯的問題。
當然,手動審查并不是檢測嵌入在 build.rs (http://build.rs/) 文件中巧妙偽裝的惡意軟件的實用方法,但它至少讓我了解了我們正在處理的攻擊面的規模。令人驚訝的是,我們審查出來自各種第三方的大約 5700 行代碼,用于操作文件、目錄和環境變量,并在我的計算機上運行其他程序。 我不確定這個問題是否有更好的解決方案,但是,如果你的目標是構建可信賴的固件,請警惕 Rust 廣泛的軟件供應鏈攻擊面。
無法復現別人的 Rust 構建
我對 Rust 的最后一點看法是,一臺計算機上的構建無法在另一臺上復現。我認為這主要是因為 Rust 將源代碼的完整路徑作為內置到二進制文件中調試字符串的一部分。
這導致了一些糟糕的情況,例如我們在 Windows 上構建的工作成功了,但在 Linux 下卻失敗了,因為二者的路徑名非常不同,這會導致一些內存對象在目標內存中被轉移。 公平地講,這些失敗是由于 Xous 中存在錯誤,這些錯誤已經得到修復。
但是,最終仍會有用戶向我們報告我們無法復現,因為他們在構建系統上的路徑與我們的不同。
最后,我想說盡管這里列出了所有的怨言,但如果能重來,Rust 仍然是我們用于構建 Xous 所用語言的有力競爭者。我用 C、Python 和 Java 完成了很多大型項目,所有這些項目最終都背負著「不斷增加的技術債務」,而 Rust 可以規避這些問題。
審核編輯 :李倩
Rust 語言因其并發安全性而深受眾多開發者的喜愛,曾在多個榜單上獲評最受歡迎編程語言。然而,現在有人花費大量時間編寫 10 萬行 Rust 代碼之后,撰寫博客闡明 Rust 語言的一系列缺點,以下是博客的主要內容。 我深入研究 Rust 是為了改進由 Xobs 編寫的 Xous 操作系統。Xous 是一個用純 Rust 編寫的微內核消息傳遞操作系統,是為了輕量級 (IoT / 嵌入式規模) 的安全優先平臺(例如 Precursor)而編寫的,用于 MMU 的硬件強制型頁面級內存保護。
一年來,我們為 Xous 操作系統添加了許多功能,包括網絡 (TCP/UDP/DNS)、用于模態和多語言文本的中間件圖形抽象、存儲(以加密的形式)、PDDB、可信啟動(trusted boot)以及密鑰管理庫等。
我們決定編寫自己的操作系統而不是使用 SeL4、Tock、QNX 或 Linux 等現有實現,是因為我們想真正了設備中每一行代碼都在做什么。特別是對于 Linux,它的源代碼庫非常龐大且動態,即使開源,也不可能搞清其內核中的每一行代碼。
因此,Xous 僅支持我們的平臺,以盡可能避免內核不必要的復雜性。 這樣減少應用范圍還意味著我們還可以充分利用 CPU 在 FPGA 中運行的優勢 。因此,Xous 以一種不尋常的 RV32-IMAC 配置為目標:具有 MMU + AES 擴展的配置。 FPGA 意味著我們有能力在硬件級別上修復 API 錯誤,從而使內核更加精簡。
這對于從 RAM 中處理諸如掛起和恢復之類的抽象破壞(abstraction-busting)進程尤其重要。 我們創建 Xous 時研究了大量的系統編程語言,最終 Rust 脫穎而出。當時它剛剛開始支持 `no-std`,它的特點是強類型、內存安全,具有良好的工具和新型生態系統。我個人是強類型語言的忠實擁護者,而內存安全性不僅有利于系統編程,還能使優化器更好地生成代碼,并且 Rust 適用于并發。
實際上,我希望 Precursor 有一個支持標記指針和內存功能的 CPU,類似于 CHERI。于是我們和 CHERI 研發團隊進行了一些討論,但顯然他們非常專注于 C 語言,也沒有足夠的帶寬來支持 Rust。
總體而言,C 比 Rust 需要 CHERI 多得多,他們的選擇是符合資源優先原則的。我們不使用 C 語言,但出于安全性考慮,我希望有一天 Rust 中會存在硬件強制型胖指針(fat pointer)。
然而,Rust 語言絕不是完美的,甚至給我們的開發帶來了很多問題。下面我列舉一下 Rust 的缺點。
語法混亂復雜
我發現 Rust 語法密集、繁重且難以閱讀,例如:
Trying::<&'aheavy>(syntax,|like|{this.can_be(maddening)}).map(|_|())?;
簡單來說,上面的代碼類似于在對象(實際上是 `struct`)上調用一個名為「to_read」的方法。 還有一種不遵循 Rust 語法規則的宏和指令也能運行:
#[cfg(all(not(baremetal),any(feature=“hazmat”,feature=“debug_print”)))]
上面的語句中最令我困惑的是使用‘=’來表示等價而不是賦值,因為配置指令中的內容不是 Rust 代碼,它就像一個完全獨立的元語言。再比如,Rust 宏的可讀性也存在問題——即使是我自己編寫的一些 Rust 宏也「只是勉強工作」。
一種可靠的語言不應該存在這些語法問題。 Rust 的確很強大,它的標準庫中包含 HashMaps、Vecs 和 Threads 等數據結構,豐富且可用性高。然而,Rust 的「std」庫并沒有為我們構建可審計的代碼庫帶來任何好處。
Rust 不夠完善
我們編寫 Xous 的代碼時,引入了一個叫作「const generic」的新類型。在此之前,Rust 沒有原生能力來處理多于 32 個元素的數組,這個限制令人抓狂。 在編寫 Xous 的過程中,Rust 的內聯匯編、工作空間等功能逐漸成熟,這意味著我們需要重新審視已經寫好的代碼,以使關鍵的初始啟動代碼集成進我們構建的系統。
Xous 開發的第一年都是使用’no-std’完成的,代價是占用大量內存空間且復雜性高。盡管可以編寫一個只有預先分配的、靜態大小的數據結構的操作系統,但為了適應最壞情況下的元素數量,因此我們不得不推出一些自己的數據結構。 大約一年前,Xobs 將 Rust 的 `std` 庫移植到 Xous,這意味著我們可以在穩定的 Rust 中訪問堆,現在 Xous 與特定版本的 Rust 綁定。 `std` 庫從根本上將內存分配、線程創建等「不安全」的硬件結構轉變成了「安全」的 Rust 結構。
然而,我必須不斷提醒自己,擁有 `std` 庫并不能消除關鍵代碼中的安全漏洞風險——它只是將許多關鍵代碼移動到標準庫中。 Rust 有固定的更新周期,這意味著我們也必須定期更新 Xous ,以保持與語言的兼容性。 但這可能是不可持續的。
最終,我們需要鎖定代碼庫,但我沒有明確的退出策略。也許我們可以考慮仍然使用 `no-std` 以獲得穩定的 `alloc` 功能來訪問堆。但這樣我們就還需要使用 Vec、HashMap、Thread 和 Arc/Mutex/Rc/RefCell/Box 構造等,以使 Xous 能夠被有效編碼。
Rust 在供應鏈安全方面堪憂
在 rustup.rs 安裝文件中有如下代碼:
`curl--proto'=https'--tlsv1.2-sSfhttps://sh.rustup.rs|sh`
用戶可以下載腳本并在運行之前對其進行檢查,這似乎比 vscode 的 Windows .MSI 安裝程序好得多。但是,這種做法遍及整個構建生態系統,讓我對通過 crates.io 生態系統發起的軟件供應鏈攻擊的可能性感到不安。 Crates.io 也存在一種拼寫錯誤,很難確定哪些 crate 是好或壞;一些完全按照用戶想要的名稱命名的 crate 放棄提供所需功能,而積極維護的 crate 必須采用不太直觀的名稱。當然,這不是 Rust 獨有的問題。 還有一個事實是,依賴項是鏈式的。也就是說當你從 crates.io 拉入一個東西時,你也會拉入該 crate 的所有從屬依賴項,以及它們所有的 build.rs (http://build.rs/) 腳本,這些最終都將在你的機器上運行。
因此,僅審核 Cargo.toml 文件中明確指定的 crate 是不夠的——您還必須審核所有相關 crate 是否存在潛在的供應鏈攻擊。 幸運的是,Rust 確實允許您使用 Cargo.lock 文件將 crate 固定在特定版本,并且可以完全指定依賴 crate 。我們試圖在 Xous 中通過發布 Cargo.lock 文件并將我們所有的一階相關 crate 指定為次要修訂的策略來緩解這個問題。
然而,我們的大部分調試和測試框架都依賴于一些相當花哨和復雜的 crate,這些 crate 引入了大量的依賴項,即使我嘗試為我們的目標硬件運行構建,在主機上運行的依賴 crate 和 build.rs 腳本還是被構建。 針對這個問題,我編寫了一個名為「crate-scraper」的小工具,它為我們的 Cargo.toml 文件中指定的每個源下載源包,并且將它們存儲在本地,這樣我們就可以獲得用于構建 Xous 版本的代碼快照。
它還運行一個快速的「分析」程序——搜索名為 build.rs 的文件并將它們整理到一個文件中,這樣我就可以更快地通過 grep 查找明顯的問題。
當然,手動審查并不是檢測嵌入在 build.rs (http://build.rs/) 文件中巧妙偽裝的惡意軟件的實用方法,但它至少讓我了解了我們正在處理的攻擊面的規模。令人驚訝的是,我們審查出來自各種第三方的大約 5700 行代碼,用于操作文件、目錄和環境變量,并在我的計算機上運行其他程序。 我不確定這個問題是否有更好的解決方案,但是,如果你的目標是構建可信賴的固件,請警惕 Rust 廣泛的軟件供應鏈攻擊面。
無法復現別人的 Rust 構建
我對 Rust 的最后一點看法是,一臺計算機上的構建無法在另一臺上復現。我認為這主要是因為 Rust 將源代碼的完整路徑作為內置到二進制文件中調試字符串的一部分。
這導致了一些糟糕的情況,例如我們在 Windows 上構建的工作成功了,但在 Linux 下卻失敗了,因為二者的路徑名非常不同,這會導致一些內存對象在目標內存中被轉移。 公平地講,這些失敗是由于 Xous 中存在錯誤,這些錯誤已經得到修復。
但是,最終仍會有用戶向我們報告我們無法復現,因為他們在構建系統上的路徑與我們的不同。
最后,我想說盡管這里列出了所有的怨言,但如果能重來,Rust 仍然是我們用于構建 Xous 所用語言的有力競爭者。我用 C、Python 和 Java 完成了很多大型項目,所有這些項目最終都背負著「不斷增加的技術債務」,而 Rust 可以規避這些問題。
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
cpu
+關注
關注
68文章
10889瀏覽量
212401 -
操作系統
+關注
關注
37文章
6859瀏覽量
123502 -
編程語言
+關注
關注
10文章
1949瀏覽量
34850
原文標題:編寫完10萬行代碼,我發了篇長文吐槽Rust
文章出處:【微信號:CVSCHOOL,微信公眾號:OpenCV學堂】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
gitee 支持的編程語言有哪些
些 Gitee 支持的常見編程語言: Python :一種廣泛使用的高級編程語言,以其清晰的語法和代碼可讀性而聞名。 Java :
Triton編譯器支持的編程語言
編寫和優化深度學習代碼。Python是一種廣泛使用的高級編程語言,具有簡潔易讀、易于上手、庫豐富等特點,非常適合用于深度學習應用的開發。 二、領域特定語言(DSL) Triton也提供
編程語言的誤區與常見問題
: 選擇編程語言時,應考慮項目需求、個人興趣以及語言的適用性。例如,如果你對Web開發感興趣,那么學習JavaScript可能是一個好選擇。 認識到沒有
C語言與其他編程語言的比較
C語言作為一種歷史悠久的編程語言,自其誕生以來,一直在軟件開發領域扮演著重要角色。它以其高效、靈活和可移植性強的特點,成為了系統級
abb工業機器人的編程語言是什么
ABB工業機器人的編程語言主要是RAPID(Robot Application Programming Interface for Development),它是一種高級編程
cnc系統一般可用幾種編程語言
。CNC系統廣泛應用于機械制造、汽車制造、航空航天等領域。 CNC系統的編程語言是實現CNC系統控制功能的關鍵技術之一。以下是對CNC系統可用編程語
verilog與其他編程語言的接口機制
Verilog是一種硬件描述語言,用于描述數字電路的行為和結構。與其他編程語言相比,Verilog具有與硬件緊密結合的特點,因此其接口機制也有一
plc編程語言與c語言的聯系 c語言和PLC有什么區別
PLC編程語言與C語言的聯系 PLC(可編程邏輯控制器)是一種針對自動化控制系統的特殊計算機。PLC編程
plc編程語言有幾種,一般常用有哪些
PLC(可編程邏輯控制器)是一種用于自動化控制系統的電子設備,它使用特定的編程語言來控制和監視機器或過程。常見的PLC編程
評論