Z3不能直接验证C++代码,因其是SMT求解器而非编译器或解析器;需手动将C++逻辑(如断言、循环不变量)翻译为SMT-LIB格式的逻辑公式再交由Z3求解。

Z3 不能直接验证 C++ 代码的正确性——它不解析 C++ 语法,也不执行或编译 C++ 程序。你要做的,是把 C++ 中的关键逻辑(比如循环不变量、函数前置/后置条件、断言)手动翻译成 Z3 能理解的逻辑公式,再交由 Z3 求解。
为什么不能直接输入 .cpp 文件给 Z3?
Z3 是一个 SMT 求解器,它处理的是已形式化的逻辑表达式(如:整数线性算术、位向量、数组、未解释函数等),不是源码分析器或编译器前端。它没有 C++ 词法分析器、语法树构建器或语义模型。
-
z3命令行工具只接受 SMT-LIB v2 格式的文本(.smt2文件)或通过 API 构造的表达式 - C++ 的指针运算、内存布局、模板实例化、异常控制流等,在 Z3 中没有直接对应语义
- 即使使用 Clang AST 提取逻辑,也必须由你定义“哪些行为需验证”并映射为约束(例如:将
for (int i = 0; i 显式建模为归纳变量 + 不变量断言)
典型流程:从 C++ 断言到 Z3 公式
以一个简单函数为例:
int abs_diff(int a, int b) {
return (a > b) ? a - b : b - a;
}你想验证:对所有整数 a, b,结果非负且等于 |a - b|。
你需要做三件事:
- 用 Z3 的
Int类型声明两个变量:a,b - 定义输出变量
res,并添加分支等价约束:Or(And(a > b, res == a - b), And(a - 添加待验证性质作为否定后检查是否可满足(反证法):
Not(res >= 0);若 Z3 返回unsat,说明该性质恒成立
Python + z3py 示例:
立即学习“C++免费学习笔记(深入)”;
from z3 import *
a, b, res = Int('a'), Int('b'), Int('res')
s = Solver()
s.add(Or(And(a > b, res == a - b), And(a <= b, res == b - a)))
s.add(res < 0) # 否定待证性质
print(s.check()) # 输出 unsat → 性质成立
常见陷阱与绕不开的取舍
实际工程中卡住的地方往往不是 Z3 用法,而是建模本身:
- C++ 的未定义行为(如带符号整数溢出)在 Z3 中默认按数学整数处理;若要模拟 32 位补码,必须显式使用
BitVec(32)并重写所有运算 - 动态内存(
new/delete)、函数指针、虚函数调用无法直接建模;只能抽象为未解释函数(Function('malloc', IntSort(), IntSort())),但会大幅削弱验证力度 - 循环必须人工归纳:Z3 不自动推导循环不变量;你得自己写出不变量公式,并用
Implies表达“进入前成立 ⇒ 执行一次后仍成立” - 浮点数要用
FPSort(8, 24)(单精度)等,且需启用fp理论,而 C++float的实际行为(如 FMA、舍入模式)仍需额外建模
真正能落地的场景,是小而关键的算法模块(如加密辅助函数、协议解析边界检查、ring buffer 索引计算),配合人工提取的规约。指望 Z3 “全自动验证整个 C++ 项目”,目前只是论文标题里的动词。











