[论文阅读] 软件工程 | GPS算法:用“路径摘要”当向导,软件模型检测从此告别“瞎找bug”

GPS算法:用"路径摘要"当向导,软件模型检测从此告别"瞎找bug"

论文信息

项目 详情
论文原标题 Software Model Checking via Summary-Guided Search (Extended Version)
主要作者及机构 1. Ruijie Fang(University of Texas at Austin, USA) 2. Zachary Kincaid(Princeton University, USA) 3. Thomas Reps(University of Wisconsin-Madison, USA)
APA引文格式 Fang, R., Kincaid, Z., & Reps, T. (2025). Software Model Checking via Summary-Guided Search (Extended Version). ACM Transactions on Programming Languages and Systems, 1(1), 1-36. https://doi.org/10.1145/nnnnnnn.nnnnnnn
核心领域 软件模型检测、静态分析、自动化测试
开源资源 - Docker镜像:https://hub.docker.com/r/ruijiefang/gps-oopsla25-ae/ - 基准与代码:https://doi.org/10.5281/zenodo.16914158

一段话总结

本文提出一种名为GPS(Guided by Path Summaries) 的软件模型检测算法,将程序模型检测转化为"有向导的状态搜索":通过静态分析生成的"路径摘要"(过近似输入输出关系的公式),既剪枝掉不可行路径、减少无效搜索,又引导测试生成以探索未覆盖状态;其创新的"两层搜索策略"(深度优先执行测试+广度优先生成测试)能高效处理"长输入依赖错误路径"(如需循环1000次的bug),还通过"gas变量 instrumentation"保证了"反驳完备性"(只要有bug,给足够时间就一定能找到)。在SV-COMP(ReachSafety-Loops类别)及"锁钥难题"(Lock & Key)等基准测试中,GPS在解决数量和运行时间上均超越现有顶尖模型检测工具。

研究背景:软件模型检测的"三难困境"与"痛点案例"

要理解GPS的价值,先得搞清楚它解决了什么"老大难"问题。软件模型检测的核心目标是证明程序安全(无bug)或找到bug(反例输入),但现有技术长期陷入"三难困境":

1. 现有三大技术的"先天缺陷"

技术类型 优点 致命缺点 类比场景
静态分析 能证明程序安全 不能找bug(过近似导致无法反驳) 医院"全面体检":能查慢性病,但漏诊急性病
自动化测试 能找bug(生成测试用例) 不能证明安全(覆盖不全) 警察"巡逻抓小偷":能抓现行,但不能保证无贼
传统模型检测 既能证安全又能找bug 慢、易超时、可能不终止(搜索空间爆炸) "地毯式搜索":能找全,但费时间且可能迷路

2. 两大典型痛点案例(论文重点解决)

痛点1:"锁钥难题"(Lock & Key)------找不到"开门的钥匙"

比如论文中的EX-1程序 (图1):要触发断言错误,需满足两个条件:① 循环执行至少1000次;② 输入N=1000("钥匙")。现有工具的问题:

  • 测试工具(如DART):随机生成N,很难碰巧选中1000,且循环1000次会超时;
  • 传统模型检测(如BMC):按路径长度递增搜索,没到1000次就耗尽资源。
痛点2:"长路径陷阱"------绕不出"无限循环"

比如论文中的状态机程序 (图9):要触发错误,需依次输入"D→O→G"(状态机切换)+"C→A→T"(输入变量)。现有工具可能陷入"无限循环":每次选c=0(非关键输入),永远到不了错误状态,导致Explore子程卡死。

3. 核心需求:需要一种"又准又快又全"的方法

  • 准:能精准定位"有效路径",不做无效搜索;
  • 快:能跳过冗余路径,快速找到长依赖bug;
  • 全:只要有bug,就一定能找到(反驳完备),同时能证明安全。

创新点:GPS的"四大独门绝技"

GPS的突破在于把静态分析的"精准导航"、测试的"高效探索"、模型检测的"完备性"捏合成一个整体,核心创新有四个:

1. 摘要引导测试:不"瞎试",只试"可能有bug的路径"

传统测试是"广撒网",GPS是"精准钓鱼"------用静态分析生成的"路径摘要"(过近似输入输出公式)指导测试生成:

  • 摘要Sum(G,u,v):代表从节点uv的所有路径的"输入输出关系"(比如"min'=i'=kk≥1000");
  • 测试生成逻辑:若w(π)∘Sum(G,dst(π),t)(路径π+从π终点到错误的摘要)可满足,则从模型中提取"可能触发bug的测试用例",避免随机试错。

比如EX-1中,摘要直接给出"k≥1000",GPS直接生成N=1000的测试,一次就命中bug。

2. 死端插值:生成"一劳永逸"的不变量

当测试生成失败(测试到不了错误),GPS不是直接放弃,而是提取"死端插值":

  • 死端:路径π的所有延伸都到不了错误(比如EX-2中"r≥3"的路径,不可能满足"r=2"的错误条件);
  • 插值:从"w(π)∘Sum(...)不可满足"的证明中提取的状态公式(如"2|x",表示x是偶数),能证明"所有延伸路径都不可行"。

比如EX-3中,死端插值"2|x"直接证明"x永远是偶数,不可能等于1",一次性覆盖所有相关路径,不用逐个验证。

3. 两层搜索策略:兼顾"深度探索"与"广度覆盖"

GPS用"广度优先生成测试+深度优先执行测试"的组合策略:

  • 广度优先:从路径树的"前沿"(未探索路径)中选路径生成测试,避免陷入某一条无效路径;
  • 深度优先:执行测试时深入探索路径,快速覆盖长路径。

这种策略既不会像传统深度优先那样"一条路走到黑",也不会像纯广度优先那样"浅尝辄止",特别适合长输入依赖路径。

4. gas instrumentation:给"无限循环"装"刹车"

为了保证"反驳完备性"(只要有bug就一定能找到),GPS给程序加了个gas变量(类似"倒计时"):

  • 初始化:gas为非确定正整数;
  • 循环处:每次循环gas--,且gas≥0(否则退出循环);
  • 作用:强制Explore子程不会陷入"无限循环",保证所有可能路径都会被公平探索。

比如状态机程序中,gas变量会迫使测试生成"让状态机前进"的输入(如c=68),否则gas耗尽就退出,避免卡死。

研究方法:GPS算法的"三步拆解"

GPS的逻辑链条非常清晰,可拆成"基础版(GPSLite)→完整版(GPS)→完备性保障(gas)"三步:

步骤1:GPSLite------核心逻辑的"简化版"

GPSLite是GPS的"骨架",专注于"找bug+死端检测",流程如下:

  1. 初始化 :路径树T(存已探索路径)、前沿队列frontierQueue(存待探索路径),初始只有空路径;
  2. 循环探索
    • 从队列取路径π,用Check+原语判断"w(π)∘Sum(G,dst(π),t)是否可满足";
    • 若可满足(SAT):调用Explore子程,从模型中提取测试用例,模拟执行并扩展路径树(若到错误则返回bug);
    • 若不可满足(UNSAT):标记π为死端,跳过(剪枝);
  3. 终止:队列空则证明安全,找到bug则返回反例。

步骤2:GPS------加入"不变量合成"的"完整版"

GPS在GPSLite基础上增加"证明安全"的能力,核心是抽象可达树(ART)

  1. ART结构 :路径树T+标签L(路径的状态公式,如"2|x")+覆盖边Cov(标记归纳不变量);
  2. 死端插值生成 :当Check原语返回UNSAT时,提取插值序列(如⊤→2|x→2|x),用Refine子程强化路径标签,标记死端;
  3. 归纳不变量检查 :用TryCover子程检查"子路径标签是否蕴含祖先标签"(如"x>1∧2|x蕴含2|x"),若满足则加覆盖边,证明循环不变量;
  4. 终止:ART无"前沿路径"(所有路径要么死端要么被覆盖)则证明安全。

步骤3:gas instrumentation------保障"反驳完备性"

为了避免Explore子程陷入无限循环,GPS对程序做"微小改造":

  1. 新增全局变量gas,初始为非确定正整数;
  2. 在每个循环头部加代码:if (gas-- < 0) break;
  3. 效果:任何测试用例的执行步数都被gas限制,Explore必然终止,且GPS会"公平探索"所有可能路径(只要有bug,总有一个gas值能覆盖错误路径)。

关键优化:离线预计算摘要

GPS频繁需要"从任意节点到错误节点的摘要",为了不重复计算,论文用Tarjan算法对偶化

  1. 反转程序控制流图(G→G^R);
  2. 定义"反向组合运算符"(F∘^R G = G∘F);
  3. 用Tarjan算法一次计算所有"单目标摘要"(从任意节点到错误节点),后续查询直接调用,效率提升线性倍。

主要成果:数据说话,GPS到底有多强?

论文用297个基准程序(SV-COMP+锁钥难题+安全例子)验证GPS,核心结果如下:

1. 三大研究问题(RQ)与结论

研究问题(RQ) 实验设计 核心结论
RQ1:GPS哪些组件最关键? 消融实验:GPS vs GPSLite(无不变量)vs GPS-nogas(无gas)vs GPS-nogas-nosum(无摘要) 1. 摘要(sum)是核心:无摘要时锁钥难题仅解决2/57; 2. gas提升稳定性:无gas时状态机例子仅解决3/6; 3. 不变量(GPS vs GPSLite):安全例子从4/9提升到9/9
RQ2:GPS vs 基础技术(CRA/Impact) 对比CRA(静态分析)、Impact(模型检测) 1. 比Impact多解决142个基准(136→278); 2. 比CRA多证明29个安全程序(156→185),且新增找bug能力
RQ3:GPS vs 顶尖工具? 对比SV-COMP 2024顶尖工具(VeriAbs/Symbiotic/CPAChecker) 1. 总解决数:GPS 278 > VeriAbs 236 > Symbiotic 183; 2. 锁钥难题:GPS 57/57全解决,VeriAbs仅28/57; 3. 运行时间:GPS平均9675s,比Symbiotic(87358s)快8倍

2. 核心贡献总结

贡献类型 具体价值
理论贡献 1. 提出"摘要引导搜索"框架,结合静态分析与测试; 2. 证明GPS的"反驳完备性"; 3. 死端插值:首次用摘要生成覆盖无限路径的不变量
工程贡献 1. Tarjan算法对偶化:离线预计算摘要,提升效率; 2. gas instrumentation:低成本实现完备性
实践贡献 1. 解决SV-COMP中多数"长路径+输入依赖"难题; 2. 开源工具与基准,供后续研究使用

关键问题

Q1:GPS如何解决"锁钥难题"中"找不到关键输入"的问题?

A:靠"摘要引导测试生成"。静态分析生成的路径摘要会直接给出"触发bug的输入约束"(如EX-1中"k≥1000"),GPS用SMT求解器从摘要中提取"关键输入"(N=1000),不用随机试错,一次就能命中。

Q2:"死端插值"和传统不变量有什么区别?

A:传统不变量(如Impact算法)是"逐路径生成",只能覆盖单条路径;死端插值是"基于摘要生成",能覆盖所有延伸路径 (比如"2|x"能证明所有"x为偶数"的路径都到不了"x=1"的错误),质量更高,减少重复计算。

Q3:为什么"gas instrumentation"能保证"反驳完备性"?

A:因为它强制"所有测试用例都有长度上限"(由gas决定),Explore子程不会陷入无限循环。GPS按"广度优先"处理前沿路径,只要有bug,总有一个gas值能覆盖错误路径的长度,且GPS会公平探索所有可能路径,最终一定能找到bug。

Q4:GPS相比传统模型检测(如Impact),为什么更快?

A:有两个关键原因:① 摘要剪枝:提前排除不可行路径,减少搜索空间;② 离线摘要:用Tarjan算法对偶化预计算所有"单目标摘要",后续查询不用重复分析循环,节省时间;③ 两层搜索:深度优先执行测试+广度优先生成测试,平衡"深度"与"广度",避免无效探索。

总结:GPS的"得与失"与未来方向

1. 核心优势

  • 高效:摘要引导+剪枝,解决长路径、输入依赖bug的效率远超现有工具;
  • 全能:既能证明程序安全(死端插值+ART),又能找bug(测试生成);
  • 可靠:gas instrumentation保证"反驳完备性",只要有bug就一定能找到;
  • 易用:开源工具+基准,可直接复用,支持线性整数算术(LIA)程序。

2. 现有局限

  • 适用范围:目前仅支持"过程内程序"(无函数调用)和"线性整数算术"(无指针、数组);
  • 摘要精度:摘要的过近似可能导致"假阳性测试"(生成的测试到不了错误),需额外处理;
  • 性能开销:不变量合成(死端插值+TryCover)会增加少量计算成本。

3. 未来方向

  • 扩展到"跨过程程序":结合Spacer等跨过程模型检测框架;
  • 支持更复杂数据类型:如数组、指针、堆内存;
  • 提升摘要精度:用更精准的代数程序分析技术(如非线性不变量)减少假阳性。
相关推荐
小xin过拟合2 小时前
day20 二叉树part7
开发语言·数据结构·c++·笔记·算法
lxmyzzs3 小时前
【图像算法 - 23】工业应用:基于深度学习YOLO12与OpenCV的仪器仪表智能识别系统
人工智能·深度学习·opencv·算法·计算机视觉·图像算法·仪器仪表识别
Learn Beyond Limits3 小时前
Multi-output Classification and Multi-label Classification|多输出分类和多标签分类
人工智能·深度学习·神经网络·算法·机器学习·分类·吴恩达
2401_858286114 小时前
OS26.【Linux】进程程序替换(下)
linux·运维·服务器·开发语言·算法·exec·进程
张同学的IT技术日记4 小时前
【奇妙的数据结构世界】用图像和代码对队列的使用进行透彻学习 | C++
算法
极客BIM工作室4 小时前
强化学习算法分类与介绍(含权重更新公式)
算法·分类·数据挖掘
KarrySmile4 小时前
Day8--HOT100--160. 相交链表,206. 反转链表,234. 回文链表,876. 链表的中间结点
数据结构·算法·链表·双指针·快慢指针·hot100·灵艾山茶府
玩转数据库管理工具FOR DBLENS4 小时前
精准测试的密码:解密等价类划分,让Bug无处可逃
数据库·单元测试·测试用例·bug·数据库开发
luckycoding5 小时前
1424. 对角线遍历 II
算法·leetcode·职场和发展