當未定義的行為導致無意義錯誤時(在 Rust 中)

https://glandium.org/blog/?p=4354

當未定義的行為導致無意義的錯誤時(在 Rust 中)

起因在於我檢視是否可能在 arm64 macOS 上使用指標驗證碼(PAC)來建立 Firefox。簡而言之,由於蘋果本質上還沒有將其最終 ABI 上游化,目前只有 Xcode clang 才能產生 PAC,而 Rust 當然不能。

然而,Rust 編譯器最近確實新增了 arm64e-apple-darwin 目標(正如上述所述,目前被明確證明是無用的),雖然沒有預建 libstd(所以需要使用-Zbuild-std 標誌)。最新的版本是 1.76.0(在撰寫時為 beta 版本)。

試過欺騙 Firefox 建置系統接受為該目標進行建置後,我得到了一個 Firefox 建置…在啟動時崩潰,並顯示:

以 MOZ_CRASH 為前綴(在 C++代碼中的 MOZ_ASSERT 或 Rust 中的 assert!())的程式碼呼叫無法使用 NS_InvokeByIndex,所以這時我在考慮是否 XPConnect 可能需要針對 arm64e 做一些調整。

但這是我通過 Mozilla try server 生成的建置。所以我進行一個本地非優化的調試建置以了解發生了什麼,結果出現了不同的錯誤訊息:

以 MOZ_CRASH 為前綴的程式碼呼叫無法使用 slice::get_unchecked,因為它要求索引在陣列範圍內。

這來自 rust libstd 中的這段程式碼:

「unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
debug_assert_nounwind!(
self < slice.len(), "slice::get_unchecked requires that the index is within the slice", ); // SAFETY: 該呼叫者保證`slice`不是懸空的,所以它不可能比`isize::MAX`更長。 // 他們還保證`self`位於`slice`的範圍之內,因此`self`不可能溢出`isize`,所以`add`的呼叫是安全的 unsafe { crate::hint::assert_unchecked(self < slice.len()); slice.as_ptr().add(self) } }」 (我貼上整段是因為這會在稍後變得重要) 我們碰到了 debug_assert_nounwind。 呼叫程式碼看起來如下: let end = atoms.get_unchecked(STATIC_ATOM_COUNT) as *const _; 而 debug_assert_nounwind 的意思是 STATIC_ATOM_COUNT 是否大於或等於陣列大小(劇透警告:兩者是等於的)。 從那時開始,我開始懷疑這可能是新 Rust 版本的更普遍問題,而不僅僅是 arm64e 的問題。我的想法好像有點對?Mozilla 自動化顯示在使用 Rust beta(目前為 1.76.0)建置時,在所有平台上都會出現崩潰。但那是一個不同、無意義的崩潰: 以 MOZ_CRASH 為前綴的程式碼嘗試完成加法運算。 但這次,它發生在與我本地獲取的崩潰相似的地方。 由於這是關於溢出加法的問題,我分別對兩個項目添加了 dbg 計數後,看見溢出消失了,但現在我獲得了一個普通的崩潰: 程序崩潰[@>::get_unchecked]

(至少仍然來自於相同對 get_unchecked 的呼叫)

問題通常是通過移除使用 get_unchecked 的整段程式碼進行解決。美好成就啊。

但這個結果太怪異了,無法就此留下。

那麼到底發生了什麼?

首先,儘管有一個 debug_assert,調試建置未對 get_unckecked 的越界使用造成問題。只有用-Zbuild-std 時才會發生。我不確定這是否是預期的情況,但我打開了一個問題來弄清楚。

其次,在我從 get_unchecked 貼上的程式碼中,hint::assert_unchecked 是在 1.76.0 中新加入的(或許在 1.76.0 中是 intrinsics::assume,並在 1.77.0 中變成了 hint::assert_unchecked,但之前是沒有的)。這就是為什麼我們的錯誤程式碼直到現在都沒有真正出現問題的原因。

那關於加法溢出呢?

這就是未定義的行為導致最佳化器做出使用者可能視為奇異的行為,但這些實際上是合理的事情(像往常一樣,這些涉及未定義行為的事情)。讓我們直接從原始程式碼開始,簡化上面原先所用的類型,構建獨立版本:

{…}

via glandium.org

February 1, 2024 at 10:49AM

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *