這篇部落格的總編輯出生於 2004 年。她每天都在使用 1997 年的視窗管理程式 Enlightenment E16。在這篇文章中,我將描述修復一個可以停止顯示、罕見且可追溯至 2006 年的 Bug 的過程。令人驚訝的是,這個問題的根源在於牛頓演算法的錯誤實作。

有些人可能會覺得奇怪,但我實際上非常喜歡將 Enlightenment E16 作為我的視窗管理程式。它可以自訂主題、易於修改、輕量級(峰值 RSS 僅 24MB!)、適合像我這樣大量使用鍵盤的使用者,最重要的是——它看起來非常漂亮:

E16 最初於 1997 年由 Carsten Haitzler 創造,並一直開發至今。大多數人已經轉向 E17 和其他較新的版本;但仍有一群硬派愛好者在使用 E16,我也是其中之一。程式碼庫相當老舊,多年來累積了許多技術債。

Bug 總是在時間緊迫時出現,而這個 Bug 可能感覺到了絕佳的機會:我正在為一門我將要教授的課程趕製幾張投影片。我有幾份使用 LaTeX 排版的講義 PDF 和練習題。在某個時刻,我在 Atril 中打開其中一份 PDF,整個桌面就凍結了。

我從 TTY 殺死了 X11 工作階段。不幸的是,這個凍結是確定性的:每次我打開那個特定的 PDF 時都會發生。

將 gdb 連接到運行中的程序顯示,所有樣本都停在 imlib2 的字體快取中,在同一個 e16 調用者之下:

重複重新連接顯示程式並未死鎖。每次調用 __imlib_font_cache_glyph_get 時,傳入的字元索引都不同(0、20、73、81、82、87、88,...)。因此,內部的字體測量正在進行;迴圈位於其外部。

經過一些摸索,我發現 Frame 8 (text.c:350 的 TextstateTextFitMB) 是問題所在。這是在中間省略號截斷迴圈中的一個 ts->ops->TextSize(ts, new_line, 0, pw, &hh, &ascent); 調用,該迴圈試圖將一個字串放入 textwidth_limit = 291 像素的寬度限制內,方法是從中間刪除字元——這在渲染 PDF 的標題時使用,而該標題恰好也是視窗的標題,對於裝飾來說太長了。

在許多樣本中轉儲該框架的局部變數,揭示了一個清晰的兩狀態振盪:

我總是看到兩次試圖截斷,永遠如此,每次都是相同的文字。

我們從最低的公分母開始——這裡很可能存在邏輯 Bug。

迴圈對我們來說尤其重要。節選如下:

這是一個牛頓風格的搜尋,它根據寬度與 textwidth_limit 的差距來估計需要刪除多少個字元(更多/更少),使用 cw = width / len_n 作為導數(平均每字元像素)。看到像這樣聰明巧妙的解決方案真是令人欣喜。但對於任何曾經實作過牛頓方法的人來說,這段程式碼都明顯地在說:「你的迭代限制在哪裡?!」牛頓方法可能無法收斂,也可能過度調整並發散——這一切都取決於起始點、函數的性質以及導數估計的品質。在此案例中,該方法永遠在兩個點之間振盪。

更糟糕的是,退出容差()很嚴格——只接受 nc2 在 [0, 3*cw) 範圍內。這也解釋了為什麼普通的短標題從未觸發它——對於較短的字串或較寬的 cw,會觸發 <= 2*cw 分支,步長變為 1,從而收斂。

我進行了三項防禦性更改,對多位元組和 ASCII 迴圈都進行了對稱應用:

任何 WM_NAME 足夠長,以至於中間省略號搜尋陷入過度調整狀態的視窗都會重現此問題。實際出現問題的例子是:

(包括破折號在內共 81 個字元,大約 291 像素的邊框標題欄位,字體平均約 3 像素/字元)。

較新不一定更好。新的軟體會帶來全新的 Bug,讓您和維護者們樂在其中,現在由於大型語言模型降低了貢獻的門檻。但有時穩定的維護者也會做荒謬的蠢事。

2026 年 4 月 3 日,我注意到 fgetxattr(54321, NULL, NULL, 0); 顯然會導致昨天 6.6.y LTS 核心崩潰。這個調用應該只返回 -1 並將 errno 設置為 EINVAL,因為路徑無效,但一個穩定的維護者卻將其完全修補掉了。

然後,那個糟糕的提交被回退了,在 4 月 8 日。儘管引入了明顯的拒絕服務攻擊向量,但沒有分配 CVE。

如果這是日常工作中無意間發生的事情 [1],那麼當供應鏈被破壞,惡意行為者故意引入 Bug 時會發生什麼?真是令人難以置信。當 XZ 後門被引入時,我正在我的 Debian Sid 筆記型電腦上瀏覽新聞,同時在背景編譯一些程式碼。我得知 XZ Utils 中存在一個後門,可能由一個國家行為者在 v5.6.0 版本中引入。回想起我確實運行著一個最新的發行版並經常更新的事實,我立即運行了 apt list --upgradable | grep xz-utils。果然,我從鼻孔裡噴出的咖啡漬 [2] 在我的筆記型電腦上很難處理。

另一方面,由有能力的開發者維護的舊軟體私有 checkout 中的 Bug 數量將單調減少。如果我需要一個功能,我會自己實作。如果存在問題,我只能怪自己。沒有供應鏈可以被破壞,如果一個有決心、有針對性的國家行為者想要我機器的 sudo 權限——他們總會找到辦法的。哦,還有,我可能不會使用我以前使用的 WM(XFWM)更新將帶來的任何功能。

Der Notfall ist der Normalfall. ➔

早上 5:30 不是我寫作的最佳時段。➔