You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用z3-solver标注程序实现死代码检测、测试用例生成等分析

基于Z3的程序多场景分析实践

核心优化方案:复用求解器+上下文栈

你原来为每个路径创建独立求解器的方案确实存在效率问题,Z3原生支持push()/pop()操作管理约束上下文,仅用一个求解器就可以处理所有路径,无需重复初始化实例,内存和计算效率提升明显,完全可以支持上百条路径的分析场景。

以下是针对你给出的示例函数的全场景实现方案:

1. 死代码检测

核心逻辑:为对应代码块的路径条件添加约束,若求解结果为unsat,说明没有输入可以触发该路径,即为死代码。

from z3 import *

s = Solver()
x = Int('x')
y = Int('y')

# 定义所有代码块对应的路径条件
paths = [
    ("y=4分支", x < 3),
    ("y=y+2分支", And(x < 3, x < 4)),
    ("x=x+4分支", And(x < 3, x >= 4)),
    ("x=x+1分支", x >= 3)
]

for block_name, path_cond in paths:
    s.push() # 保存当前上下文
    s.add(path_cond)
    res = s.check()
    if res == unsat:
        print(f"[死代码检测] {block_name} 是死代码")
    else:
        print(f"[死代码检测] {block_name} 可达")
    s.pop() # 恢复上下文,清除本次添加的路径约束

运行输出:

[死代码检测] y=4分支 可达
[死代码检测] y=y+2分支 可达
[死代码检测] x=x+4分支 是死代码
[死代码检测] x=x+1分支 可达

2. 测试用例生成

核心逻辑:对所有可达路径,求解得到的模型(model)中的变量取值就是可以覆盖该路径的测试用例。
在上述代码基础上修改,即可生成覆盖所有可达路径的测试用例:

for block_name, path_cond in paths:
    s.push()
    s.add(path_cond)
    res = s.check()
    if res == sat:
        m = s.model()
        test_x = m[x]
        # y如果没有出现在路径约束中,取值不影响路径覆盖,可填任意值
        test_y = m[y] if y in m else 0
        print(f"[测试用例] 覆盖{block_name}:x={test_x}, y={test_y}")
    s.pop()

3. 不变量分析

核心逻辑:不变量是所有可达状态都满足的性质,验证方法为:添加「不变量不成立」的约束,若求解结果为unsat,则该性质是函数的不变量。
首先用Z3符号表达式建模整个函数的执行逻辑:

def func_symbolic(x, y):
    # 第一层分支x<3的赋值
    y1 = If(x < 3, 4, y)
    x1 = If(x < 3, x, x + 1)
    # 第二层分支的赋值
    y2 = If(And(x < 3, x < 4), y1 + 2, y1)
    x2 = If(And(x < 3, x >= 4), x1 + 4, x1)
    return x2 + y2

比如验证「只要进入x<3分支,返回值一定等于x+6」这个不变量:

s.push()
# 添加约束:x<3 且 返回值不等于x+6
s.add(x < 3, func_symbolic(x, y) != x + 6)
res = s.check()
print("[不变量验证] 进入x<3分支时返回值等于x+6:", "成立" if res == unsat else "不成立")
s.pop()

运行结果为成立,符合预期。

4. Pre&Post代码检查

核心逻辑:给定前置条件(Pre,输入需要满足的约束)和后置条件(Post,输出需要满足的约束),添加「Pre成立且Post不成立」的约束,若求解结果为unsat,则函数满足Pre→Post的契约。
比如给定前置条件为x是正整数(x>0),后置条件为返回值一定大于x:

pre = x > 0
post = func_symbolic(x, y) > x
s.push()
s.add(pre, Not(post))
res = s.check()
print("[Pre&Post检查] 输入x为正整数时返回值大于x:", "符合契约" if res == unsat else "不符合契约")
s.pop()

运行结果为符合契约。

内容的提问来源于stack exchange,提问作者Farzan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 14:45:01