工程趣聞 2026 年 8 月 13 日

2026-08-13 — Tailscale 與 Antithesis 揪出 16 年 SQLite WAL bug、fearless_simd v0.7 補齊 64-bit SIMD、Signal 自動金鑰驗證上線

primary=https://tailscale.com/blog/sqlite-wal-reset-bug primary=https://linebender.org/blog/fearless-simd-0-7/ primary=https://signal.org/blog/automatic-key-verification/

Tailscale 如何協助揪出潛伏 16 年的 SQLite WAL-Reset Bug

Tailscale Blog · 2026-08-12

Tailscale 在 2024 年 8 月到 2025 年初的六個月間遇到 19 次資料庫損毀事故,工程師 Alex Chan 在 2026 年 8 月 12 日發布的文章中還原了整個追蹤過程。最終問題被鎖定在 SQLite 的 WAL(Write-Ahead Log)子系統裡一個存在 16 年的資料競爭(data race),修正落在 SQLite 3.51.3。同一天,實際參與重現這個 bug 的測試公司 Antithesis 也發了一篇對照文章,補上另一半故事。

原本的問題

SQLite 的 WAL 模式會先把寫入動作記錄到 WAL 檔,之後由 checkpoint 動作把 WAL 內容搬回主資料庫檔案,完成後重置 WAL。bug 出在 checkpoint 進行「重置」的瞬間,如果剛好有另一個連線在同一時刻寫入,系統會誤判某些 page 已經搬移完成,實際上那些 page 從未真正寫入主檔案,資料因此永久消失且不會回報任何錯誤。這個問題自 SQLite 3.7.0(2010 年)就存在,只在同一檔案有多個連線、分屬不同執行緒或程序、且同時寫入與 checkpoint 時才會觸發,機率極低。Tailscale 因為採用較激進的手動 checkpoint 策略,等於把發生機率硬生生拉高到「統計上必然發生」。

採用的方法

Tailscale 先排除了近期程式碼變更的可能性,再建立一套交易紀錄重播管線,逐筆重放 SQL 操作,發現有些明明已提交的寫入會無聲消失。透過付費支援合約找到 SQLite 核心開發者後,對方寫了一個叫 tmstmpvfs 的 VFS shim,用來詳細追蹤資料庫的 checkpoint 行為。與此同時,Antithesis 的工程師 Carl Sverre 在自家部落格描述了另一條路徑:他們把 SQLite 3.51.2 接上自製的並發工作負載(workload.c),在 Antithesis 的確定性模擬環境裡跑,靠因果分析(causality analysis)把問題範圍收斂到「幾分之一秒內」,15 分鐘就重現出這個 bug。

實際效果

SQLite 3.51.3 在 checkpoint 函式裡加了一個檢查,用來偵測 WAL 是否已被另一執行緒重置。Tailscale 另外在自家程式碼的 commit 070c921dea03f793cbbbd9d39551d0ad26136113 加上告警日誌,並部署了一套暱稱「party mode」的告警機制,用來偵測「觸發條件出現但沒有真的丟資料」的情況,兩個月後確認修正確實有效。Antithesis 這邊則是把同一套工作負載跑在 3.51.3 上驗證問題已消失。文章也提到後續在 SQLite 3.52.0 又出現一個表達式索引過期的問題,已在 3.53.0 加入自我修復機制解決。

原始來源:Tailscale BlogAntithesis Blog


fearless_simd v0.7:Rust 安全 SIMD 函式庫補上 64-bit 整數與 SSE2

Linebender Blog · 2026-08-12

Linebender 專案的 fearless_simd(一套主張「把 unsafe 從 SIMD 裡拿掉」的 Rust 函式庫)在 2026 年 8 月釋出 v0.7.0,作者是 Shnatsel。這個版本補齊了 64-bit 整數向量、擴充了泛型設計,並第一次提供獨立的 SSE2 實作層。GitHub 上對應 release 的 commit 是 57ec21aa813cc1bbe0a5f167c2627f5f610b1d05,最低支援版本(MSRV)拉到 Rust 1.89

核心改動

fearless_simd 讓開發者不用手寫 CPU 專屬的 intrinsics,就能安全存取 SIMD 指令,並在執行期依硬體能力動態選擇實作。v0.7 新增 i64x2/i64x4/i64x8u64x2/u64x4/u64x8 等 64-bit 整數向量類型,過去因為 AVX2 之類指令集對 64-bit 整數支援零散而一直缺席,這次要靠 v0.5 引入的編譯期安全追蹤機制才補上。同時 SimdBase trait 統一了整數與浮點向量的操作介面,新增的 Bytes trait 讓不同向量之間可以做泛型 bitcast。

  • 新增獨立 Sse2 支援層,直接寫死 intrinsics,不再仰賴自動向量化 fallback
  • swizzle_dyn / swizzle_dyn_precise:任意寬度的動態 byte shuffle
  • shift_elements_left/rightrotate_elements_left/right 等便利函式
  • 向量間 widen/narrow 轉換可選擇 wrapping、saturating 或平台最佳化行為

API 也有破壞性調整:load_interleaved_128_* 改名為 load_four_interleaved_*new_unchecked() 改名為 assume_supported(),原本 204 個逐類型的陣列轉換方法整併成 load_array/store_array 這類泛型版本。

影響範圍

整併 API 之後,編譯時間反而縮短了約三分之一,產生的程式碼與 metadata 體積也明顯變小,x86 平台上的 8-bit 位移運算另外做了最佳化。專案規劃 v1.0 於 2026 年 9 月初釋出,之後不再有 breaking change,AVX-512 支援則排在後續版本。維護者在文章結尾邀請社群在 GitHub 或 Zulip 上針對 pre-1.0 的最後一批 API 調整提意見。

原始來源:Linebender Blogfearless_simd GitHub Releases


Signal 推出自動金鑰驗證,把「safety number」比對自動化

Signal Blog · 2026-08-11

Signal 工程師 Katherine Yen 在 2026 年 8 月 11 日的部落格文章中介紹了「自動金鑰驗證」功能。這個功能用一套稱為 key transparency 的系統,讓使用者不用再手動比對安全碼(safety number),就能確認自己拿到的公開金鑰沒有被竄改。

背景

Signal 過去仰賴一組安全碼讓兩個使用者面對面或透過另一個管道核對指紋,藉此確認彼此看到的公開金鑰一致。如果沒人做這個比對,一個惡意的目錄伺服器操作者理論上可以偷偷替換掉某個使用者的公開金鑰,發動所謂的「Mallory in the middle」攻擊,在雙方毫無察覺的情況下讀取或竄改訊息。但實務上幾乎沒有一般使用者會主動去掃 QR code 或比對數字,這道防線形同虛設。

核心改動

Signal 的解法是把目錄伺服器的每一次金鑰變更都寫進一份不可篡改的「log tree」(文章的類比是帳本),再搭配「prefix tree」(類比索引本)讓查詢時可以做有效率的二分搜尋,而不用線性掃過整份紀錄。這份紀錄由第三方稽核者 Cloudflare 與 Trail of Bits 各自用密碼學簽章獨立驗證完整性。使用者識別碼經過一個可驗證隨機函式(VRF)處理,對應的值再用加了金鑰的雜湊函式保護,稽核者因此驗證得了紀錄一致性,卻看不到任何一筆真實的電話號碼或金鑰內容。裝置端會定期自動檢查自己的紀錄有沒有被異動,聯絡人之間收到新識別碼時也會自動核對,取代過去要求使用者手動掃描比對的步驟。這套機制參考了 IETF 的 draft-ietf-keytrans-protocol 草案並加上 Signal 自己的調整,伺服器端實作 key-transparency-server 已經開源,內部拆成負責查詢的 KeyTransparencyQueryService、負責稽核與寫入的 KeyTransparencyService 等 gRPC 服務。

影響範圍

對一般使用者而言,多數情況下不再需要主動完成「掃描安全碼」這個過去多半被忽略的儀式,金鑰是否遭竄改的檢查改為背景自動進行。手動安全碼比對功能並未被移除,仍保留給需要額外確認的場合使用。

原始來源:Signal Blogkey-transparency-server (GitHub)

End of article
0
Would love your thoughts, please comment.x
()
x