Hands-on — 把概念裝進真的工具

三篇論文讀完之後,這一頁把概念接到真正跑得動的東西上。

這一頁的指令全部來自各工具的官方 README,但我沒有在你的機器上實際跑過。 版本會變,環境會不同——遇到落差時以官方文件為準,並且回報給我修正。每一節都附了原始出處。

0 先看一眼三個工具的關係

工具輸入做法對應教材
CPAcheckerC 程式直接在軟體層做 configurable program analysisSV 2 的框架本尊、SV 3 的實作平台
CPVC 程式先翻成硬體電路(Btor2),交給硬體 model checkerSV 3 的延伸:換一個完全不同的後端
MoXIcheckerMoXI 模型直接檢查中介語言,不經過 C另一條路:統一的不是演算法而是輸入格式

三者都出自 sosy-lab(也就是 SV 2、SV 3 的作者群)。這不是巧合——SV 2 的框架讓「換零件」變得便宜,這三個工具就是換不同零件的結果。

環境方面先有心理準備:這三個都以 Linux 為主要平台。macOS 上 CPAchecker 的預設設定需要自己編 MathSAT,CPV 直接要求 Ubuntu 22.04+。用 Docker 或實驗室的 Linux 機器最省事。

1 CPAchecker

1.1 它是什麼

SV 2 定義的 configurable program analysis,實作出來就是這個工具。SV 3 講的四個演算法,也全部在這裡面。

換句話說:你讀的兩篇論文,程式碼在這裡。

1.2 安裝

官方提供三條路(見 INSTALL.md):

# 路徑 A:Debian/Ubuntu 套件(最省事)
# 先照 https://apt.sosy-lab.org/ 的說明啟用 SoSy-Lab APT repo,然後:
sudo apt install cpachecker

# 路徑 B:ZIP 檔
# 需要 Java 21 以上
sudo apt install openjdk-21-jre

# 路徑 C:容器映像(macOS 建議走這條)

Java 21 是硬性需求。 如果 java 不在 PATH 裡,要指定環境變數:

export JAVA=/usr/lib/jvm/java-21-openjdk-amd64/bin/java

官方建議至少 Ubuntu 24.04 或 Debian 13,才能完整支援現代 SMT solver。

1.3 跑第一個例子

repo 自帶範例,不必自己找程式:

bin/cpachecker doc/examples/example.c

這是預設設定。doc/examples/example.c 長這樣(節錄):

int main() {
  int i = 0;
  int a = 0;
  while (1) {
    if (i == 20) { goto LOOPEND; }
    else { i++; a++; }
    if (i != a) { goto ERROR; }
  }
  ...
}

ia 每圈同步加一,所以 i != a 永遠不成立,ERROR 到不了。但要證明這件事,驗證器必須發現不變量 i == a——這正是 SV 1 在解的問題(那個事實從哪裡來),也是 SV 3 的 refinement 在做的事。

另外有一個帶 bug 的版本 doc/examples/example_bug.c 可以對照,看工具找到反例時的輸出長什麼樣。

規格檔預設是 config/specification/default.spc,它會去找名為 ERROR(不分大小寫)的標籤和 assertion。所以上面那支程式不需要額外指定規格。

1.4 config 檔名就是教材的索引

這是這一節最值得看的地方。CPAchecker 的 config/ 目錄有 90 幾個設定檔,而檔名直接對應你讀過的論文概念

config/predicateAnalysis-ImpactRefiner-ABEl.properties
       └──── SV1 / SV2 ────┘└─ SV3 §3.2.4 ─┘└ SV3 §3.1 ┘
        predicate abstraction  IMPACT 式 refinement  blk^l

一個檔名把三篇論文串起來了。 拆開來看:

檔名片段是什麼出處
predicateAnalysispredicate abstractionSV 1 全篇、SV 2 §2.3 的 instance
ImpactRefinerIMPACT 式的 refinement 策略——把 interpolant 直接 conjoin 進 abstraction formulaSV 3 §3.2.4
ABEladjustable-block encoding 配 $\mathsf{blk}^{l}$,也就是只在 loop head 與 error location 做 abstractionSV 3 §3.1

其他值得試的設定(全部真實存在於 config/):

設定檔對應教材
bmc.propertiesSV 3 §4.1 的 BMC
bmc-incremental.propertiesBMC 逐步加大 $k$
bmc-incremental-ABEl.propertiesBMC 但改用 $\mathsf{blk}^{l}$——親手轉那個旋鈕
bmc-induction.propertiesSV 3 §4.2 的 k-induction
bmc-interpolationSequence.propertiesSV 3 §3.2.3 的 inductive interpolant 序列
combinations-bdd+impact.propertiesIMPACT 與 BDD 的組合

指定設定的兩種寫法(等價):

bin/cpachecker --config config/bmc.properties doc/examples/example.c
bin/cpachecker --bmc doc/examples/example.c

1.5 建議的練習

  1. 先用預設設定跑 example.c,確認環境沒問題
  2. 換成 bmc.properties 跑同一支程式。想想看它憑什麼給出結論——BMC 只保證 $k$ 步之內,那它對一個無界迴圈能說什麼?
  3. 換成 bmc-incremental-ABEl.properties。這一步你就親手把 $\mathsf{blk}$ 從 never 轉到 l
  4. example_bug.c,看反例輸出長什麼樣

第 2 步的疑問,正是 SV 3 §4.1 那個 forward-condition check 在回答的。

2 CPV

2.1 它是什麼

Circuit-based Program Verifier——把 C 程式翻成硬體電路,然後用硬體 model checker 去驗。

這聽起來很繞,但想法很直接:硬體驗證領域有幾十年的工具累積(ABC、AVR、Pono、rIC3),如果能把軟體問題翻譯過去,就能免費繼承那些工具的所有進步。

架構是這樣(見 README):

C 程式 ──▶ Instrumentor ──▶ Kratos2 ──▶ Btor2 電路
                                            │
                              硬體 model checker
                         (ABC / AVR / Pono / rIC3)
                                            │
                          Btor2 witness ──▶ 翻譯回軟體 ──▶ SV witness

中間的 Kratos2 負責 C → 電路的翻譯,CoVeriTeam 負責協調後端的硬體驗證器。

注意 Btor2 就是暑訓 HWMC 主題在讀的那個格式(CAV 2018)。這裡是兩個主題的交會點。

2.2 系統需求

比另外兩個嚴格:

apt-get install clang clang-format clang-tidy cpp python3 \
                python3-bitstring python3-lxml python3-pycparser

還要注意:後端的硬體 model checker 各自有自己的系統需求。

2.3 安裝與執行

# 要連同 submodule 一起 clone
git clone --recurse-submodules https://gitlab.com/sosy-lab/software/cpv.git
cd cpv
./scripts/setup.sh          # 下載並解壓 Kratos2

如果從 Zenodo 下載打包好的 tool archive,上面的 setup 可以跳過。

執行:

./bin/cpv --property <prp_file> --model {ILP32,LP64} <c_prog>

--model 指定資料模型(32 或 64 位元),--property 指定要驗的性質(可從 sv-benchmarks 取得標準的 property 檔)。

同時跑多個 CPV 實例時,記得用 --output-dir 分開輸出目錄,否則會互相衝突。

2.4 這跟你讀的論文有什麼關係

SV 3 證明了四個軟體驗證演算法是同一個框架的不同設定。CPV 把這個想法再推一步:連「要不要留在軟體領域」都可以是一個設定。

翻成電路之後,你能用的後端從「SMT solver」變成「所有硬體 model checker」。SV 3 的公平比較方法論在這裡同樣適用——只是被比較的對象換成了不同的硬體引擎。

3 MoXIchecker

3.1 MoXI 是什麼

MoXI = Model eXchange Interlingua定義見這篇),一個模型檢查的中介語言

它想解決的問題跟 SV 3 有點像,但切入點不同:

有了共通格式,工具之間就能互換,也才談得上公平比較。

3.2 MoXIchecker 是什麼

一個可擴充的 MoXI model checker。用 Python 寫,靠 PySMT 操作與求解 SMT 公式。目前支援 QF_BVQF_ABVQF_LIAQF_NIAQF_LRAQF_NRA 這幾個理論。

它的架構刻意做得很薄:

MoXI 模型 (JSON) ──▶ moxi2smt.py ──▶ init / trans / inv / query
                     (公式抽取)      (PySMT 公式)
                                            │
                                    model_checking.py
                                     (檢查引擎)
                                            │
                                      reachable / unreachable

「可擴充」是重點:因為公式抽取和檢查引擎分開了,要加一個新的 model-checking 演算法,只需要動 model_checking.py。這跟 SV 2 「把零件抽出來就能替換」的思路完全一致,只是換了一個層次。

3.3 安裝與執行

需要 Python 3.10 以上。建議用 venv 或 Python container 隔離環境:

pip install setuptools pysmt==0.9.7.dev333
pysmt-install --msat --z3        # 官方建議 MathSAT 與 Z3 這兩個後端

執行:

./bin/moxichecker <moxi-json-file>
# 例如 repo 自帶的:
./bin/moxichecker examples/QF_ABV/count2.moxi.json

或用容器(免安裝):

podman run -v $(pwd):/workdir \
  registry.gitlab.com/sosy-lab/software/moxichecker <moxi-json-file>

一個限制要知道:MoXIchecker 目前只分析單一個 reachability query。如果模型裡有多個 check-system 或多個查詢條件,只有第一個會被處理,其餘會印警告跳過。

./bin/moxichecker -h 有完整選項。

4 三條路,同一個問題

三個工具在做同一件事——判斷某個狀態到不到得了——但走的路完全不同:

表示方式求解引擎
CPAcheckerabstract state + precisionSMT solver
CPVBtor2 電路硬體 model checker
MoXIcheckerMoXI 模型PySMT + SMT solver

共同點是那個貫穿三篇論文的觀念:把「用什麼零件」變成可替換的參數。 SV 2 把它用在演算法內部(merge / stop),SV 3 用在演算法之間(blk / fcover / CEGAR),CPV 用在整個問題領域之間(軟體 / 硬體),MoXIchecker 用在輸入格式上。

看懂這一層,這三個工具就不是三個要分別學的東西,而是同一個設計哲學的三次應用。


練習建議:如果時間有限,只做 CPAchecker 那一節的四個步驟。跑通 bmc-incremental-ABEl.properties 的那一刻,你會親眼看到論文裡那個 $\mathsf{blk}$ 運算子在真實工具裡長什麼樣。