系統程式設計的前沿

系統程式碼的形式化驗證(formal verification)

測試能展示程式碼在你試過的案例上可行,卻永遠無法展示不存在壞案例——輸入太多,試不完全部。系統程式碼的形式化驗證走的是另一條路:你不是用範例去執行程式碼,而是寫下一份精確的數學規格,描述程式碼「應該」做什麼,然後建構一個證明——由機器檢查——說明對每一個可能的輸入,程式碼都符合那份規格。這是「我測了很多」與「我證明了沒有任何輸入能破壞這個性質」之間的差別。

具體而言,你用一套形式邏輯陳述規格、精確地建模程式的行為,並用證明輔助器(proof assistant)或求解器來驗證實作滿足規格。這個證明是機器檢驗的:一個小而受信任的檢查程式確認每一個邏輯步驟,所以你不是在信任某個人聲稱論證滴水不漏。這極為費工——著名的 seL4 微核心,為了幾千行 C 程式碼耗費了以人年計的證明工夫——但回報是任何測試都給不了的保證:對所陳述的性質而言,那一類臭蟲不存在,句點。它被應用之處,往往是最關鍵、最小、最被重複使用的程式碼:一個微核心、一個監督程式核心、一段密碼學常式、一個編譯器。

它之所以重要,是因為對少數幾個基礎元件而言,「已證明正確」是一項真實而稀有的成就。但要極其誠實地看待它保證了什麼、又沒保證什麼。證明只涵蓋你所指定的性質——驗證了功能正確性,你對時序或功耗旁路通道就什麼都沒說,除非你也把那些指定進去。證明假設了一個硬體模型以及烘進其中的種種假設(編譯器、硬體照規格行事、不存在模型忽略的故障);若現實違反某個假設,保證就不成立。而一份有缺陷或不完整的規格可能被證明已滿足,系統卻仍做錯事——「已證明正確」意指「已證明在這些假設下符合這份規格」,絕不是「保證不存在任何問題」。

規格:對所有輸入,核心絕不寫到某執行緒被許可記憶體之外 證明:一個機器檢驗的推導,說明這份 C 實作滿足該規格 => 測過的程式碼展示「在我試的案例上可行」;驗證過的程式碼展示「沒有輸入違反這個性質」 (但僅限「這個」性質,且僅在硬體/編譯器假設成立時)

驗證證明一份實作對所有輸入都符合一份精確規格——但僅限所陳述的性質,且僅在模型的假設之下。

「已證明正確」比它聽起來要狹義:證明只涵蓋在明確假設下(編譯器正確、硬體遵守其模型、不存在模型外的故障)所指定的性質。一份錯誤或不完整的規格,可能被一個仍會出錯的系統「滿足」,而你沒指定的性質——像時序旁路通道——就根本不在涵蓋範圍內。

又稱
machine-checked proofproven correct形式化驗證機器檢驗證明