软件模型检测简介

来源:互联网 发布:博物馆软件 编辑:程序博客网 时间:2024/06/08 08:01

1.      什么是软件模型检测(software model checking)

a)         软件模型检测是用来在程序执行过程中证明性质正确性的算法。它源于逻辑和定理证明,这两者都给出了基础问题形式化的基本概念,以及提供了分析逻辑问题的算法流程。

b)        随着软件规模的越来越大,使得人工的验证软件变得越来越难,而且人工的验证本身是否可靠也是一个很大的问题。因此,软件模型检测研究的目的就是扩展自动验证技术的应用领域,将其用于程序的推理,无论是在程序处理的验证还是性质的验证上,都要最大程度的增加自动化的比例,从而减轻人,尤其是专家程序员的工作量。

 

2.      软件模型检测的发展

    软件模型检测目前有三方面的发展,这三方面是同时发展的,有其各自的特点:

a)         程序逻辑和相关判定过程【Nelson 1981; Nelson and Oppen 1980; Shostak 1984】的发展给无限状态过程的推理提供了基本框架和基础算法。

b)        基于时序逻辑【Pnueli 1977; Emerson 1990】的自动化模型检测技术【Clarke and Emerson 1981; Queille and Sifakis 1981; Vardi and Wolper 1994】的发展为解决状态爆炸问题提供了基础算法。

c)        通过抽象解释对编译器进行分析和形式化,使得我们在无限状态的逻辑世界空间和有穷状态的算法世界之间建立起了很好的联系。

80年代到90年代期间,这三方面虽然各自有其发展,但是,之间的相互联系却很少。直到最近十几年,现代化的软件模型检测工具成为了研究领域的研究重点,上述三方面的研究也慢慢的结合到了一起。严格意义上来说,“软件模型检测工具”的说法是不太恰当的,因为当前的工具同时具备了定理证明、模型检测、数据流分析等多种传统意义上的程序分析方法。我们保留这一说法的目的是为了反映一个阶段历史的发展。

 

3.      有形枚举的模型检测(concrete enumerative model checking)

a)         有形(concrete):方法只关心程序的状态。

b)        枚举(enumerative):方法的操作对象是程序的单个状态。而符号化(symbolic)的模型检测操作的是状态的集合。

c)        有形枚举的模型检测来源于70年代末期的测试和仿真技术,尤其是对网络协议的测试技术(同一时期,还产生了对时序逻辑进行声明的技术)。之后,该方法被成功的应用在了异步信息传输协议、cache一致性协议等多个领域。

d)        方法介绍:该方法是基于对状态图的搜索遍历,找出所有可达状态的集合,再检查看错误状态是否包含在可达状态集合当中,如果是,则说明系统不安全。否则,说明系统是安全的。

e)         代表性的工具SPIN【Holzmann 1997】和MURPHI【Dill 1996】。

f)         存在问题:状态爆炸!!!

g)        解决方法:

                         i.              基于削减的技术(reduction-based techniques):找出程序行为中的等价关系,并且只考虑每个等价类中的一个成员,保证削减后的是完备的,也即原系统中有的bug,在削减后的系统中同样存在。主要的削减技术有——偏序削减(partial-order reduction)【Valmari 1992; Katz and Peled 1992; Godefroid 1996】,对称削减(symmetry reduction)【Clarke et al. 1993; Emerson and Sistla 1996; Ip and Dill 1996; Sistla et al. 2000】,基于模拟和互模拟的等价类划分来最小化系统【Bouajjani et al. 1990; Loiseaux et al. 1995; Bustan and Grumberg 2003】。

                       ii.              合成技术(compositional techniques):将原始的验证问题分解成对其子问题的安全性验证,由子问题安全可以推导出原问题安全。假设-保证推理(assume-guarantee reasoning)【Misra and Chandy 1981; Jones 1983; Stark 1985; Abadi and Lamport 1993; Abadi and Lamport 1995; Henzinger et al. 1998; Alur and Henzinger 1999】是合成推理中发展得比较好的技术。其中还用到了一些启发式的搜索技术来加快对状态空间的搜索,快速的找到系统的问题所在,例如重复加深算法(iterative deepening)【Korf 1985】、最好-优先搜索(best-first search)【Russell and Norvig 2003】、A*算法【Hart et al. 1968; Russell and Norvig 2003】。这些方法在MURPHISPIN中也都有了很好的应用。

h)        少量状态搜索(stateless search)

 

                         i.              基于深度的限界模型检测。当某一深度的执行路径全部探测完以后没有发现错误就增加深度,再重复这一过程,直到返回UNSAFE,表明发现了与待验证的安全性性质相冲突的执行。该算法的主要特点就是对待分析的程序的表示要求不是很高。我们只要做到两点就可以了:

1.         重置(reset):对程序的初始状态进行重置;

2.         执行(execute):在相应的调度策略下执行。

i)          基于执行的工具:

                         i.              Verisoft:最早使用基于执行的少量状态搜索的模型检测软件。能对若干通过消息队列进行通讯的Unix进程进行检测。

                       ii.              JavaPathFinder:对Java程序的模型检测工具。加入了许多常用的基于削减的技术来解决状态爆炸的问题。同时有多种启发式方法来搜索存储的状态空间以及使用一些技术来获得一个更高的覆盖率。

                      iii.              CMC:可以检测C语言程序在执行时,OS层级的调度。

                     iv.              MaceMC:用于检测分布式系统。

                       v.              Chess:用于检测多线程的Windows程序。

 

4.      有形符号化的模型检测(concrete symbolic model checking)

a)         基于枚举的模型检测技术受到状态和迁移关系数量的影响很明显,很容易产生状态爆炸的问题,因此在实际应用中会遇到很多的困难。这就使得研究者们把目光放在了符号化的模型检测算法上。符号化的模型检测方法是以状态集合为操作对象的,而不是单个单个的状态。符号化的表示方法能够更加简洁的表示系统的状态,而且也能够更好的表示无限状态的集合。为了能够进行验证,符号化的表示方法所表示出来的状态集合还要能够支持必要的运算操作,例如求状态集合的后继、前驱,状态集合的合并等等。

 

b)        符号化的模型检测算法的基本搜索过程和枚举的模型检测算法的搜索过程类似,只是我们现在操作的对象是状态集合(或者说是区域,region)而不是单个独立的状态。符号化的模型检测方法之所以有效的另外一个原因就是有强有力的可满足性求解工具作其后盾,如SAT【Silva and Sakallah 1996; Moskewicz et al. 2001; Een and Sorensson 2003】,BDD【Bryant 1986; Somenzi 1998】,以及SMT【Dutertre and Moura; Bruttomesso et al. 2008; de Moura and Bjørner 2008】。

c)        符号化的表示方法

                         i.              命题逻辑:SAT,BDD。

                       ii.              带有解释定理的一阶逻辑:SMT。

d)        限界模型检测【Biere et al. 1999】

                         i.              有限步的展开程序控制流程图,检查在该步数内能够找到错误状态,若找到,则返回系统不安全的信息,若找不到,则增加步数,直到步数到达上界,此时返回找不到错误状态的信息。

                       ii.              对软件的限界模型检测工具又可以分为两类:

1.         用命题逻辑生成约束,通过SAT求解器来求解:CBMC【Kroening et al.2003】,F-Soft【Ivancic et al. 2008】,Saturn【Xie and Aiken 2005】,Calysto【Babic and Hu 2008】。

2.         用适当的一阶理论来生成约束,用SMT求解器来求解。

                      iii.              限界模型检测适合于查错,即在规定步数内找到系统的错误状态。若系统是安全的,则限界模型检测无法给出完备的判定。我们可以采用其它的方法来解决对系统安全性的判定,如k-induction【Sheeran et al. 2000; de Moura and Ruess 2003】。k-induction是假设归纳不变式在程序执行路径前k步都是成立的,然后证明该不变式在k+1步时同样成立。其中,长度为k的路径是按照限界模型检测的方法进行编码的。这种基于不变式的约束式求解方法受到两方面的限制:1.要猜测出正确的不变式;2.方法的效率受制于求解非线性算术表达式的求解器的效率。因此,这种方法目前只适用于规模较小的程序的验证。

 

5.      模型检测和抽象技术

a)         对于无限状态的程序来说,符号化的可达性分析同样不能终止,或者是说要花费难以估量的时间和空间代价才有可能终止。抽象模型检测的可达性分析是在抽象域的基础上进行的,而抽象域则是通过抽象语义对程序的运行进行适当的信息捕获而得到的【Cousot and Cousot 1977】。好的抽象域和抽象语义的选择可以很好的保证算法的可靠性和有效性。

b)        基于抽象的可达状态分析

 

该算法和符号化的可达状态分析算法类似,只是用抽象域代替了符号化的状态集合。根据抽象对象的不同,也有不同的抽象方法:

1.         谓词抽象:【Agerwala and Misra 1978; Graf and Saïdi 1997; Saïdi and Shankar 1999; Das et al. 1999】,代表工具:SLAMBLAST【Beyer et al. 2007a】。Cartesian谓词抽象技术【Ball et al. 2001】是其中的代表,在系统开销和求解效率上取得了很好的平衡,并且在SLAM中关于C程序验证的部分有其相关的使用,叫做c2bp【Ball et al. 2001】。

2.         控制抽象:流敏感,流不敏感,路径敏感等【Beyer et al. 2007b】。主要是针对非递归的并发程序进行抽象,抽象成顺序执行的程序进行验证【Dwyer and Clarke 1994】。代表工具:MAGIC【Chaki et al. 2004】。

3.         各种抽象技术相结合:结合多种抽象技术,对系统的不同性质进行抽象爱那个,得到一个更加强大的分析工具。代表工具:F-Soft【Jain et al. 2006】,IMPACT【McMillan 2006】,Astree analysis tool【Blanchet et al. 2002; Blanchet et al. 2003】,BLAST

若基于抽象的可达性分析算法返回safe,则表示原系统真的是安全的;若返回unsafe,则无法判定原系统到底是safe还是unsafe的,因为在抽象的过程中省略掉了一部分信息,有可能原系统是安全的,而在抽象后的系统中却形成伪反例(不完备)。这就需要根据某些信息对抽象后的系统进行修正。基于反例的抽象修正(counterexample guided abstraction refinement)就是其中之一。

 

6.      抽象修正技术

a)         通常来说,抽象的模型检测技术是可靠的,也即抽象系统是安全的可以推出原系统也是安全的,但是抽象的模型检测方法是不完备的,也即在原系统是安全的情况下,抽象系统有可能会得到一个错误的反例。因此,我们需要判断哪些反例是真的,即在原系统中存在的,哪些反例是假的,即在原系统中不可能存在的。出现后一种情况时,我们希望模型检测算法能够自动的修正,得到一个新的抽象域重新进行检测。这种修正有可能是基于找到的伪反例(counterexample-guided refinement)【Ball and Rajamani 2000b; Clarke et al. 2000; Saidi 2000】,也有可能是其它的策略,例如:局部削减(localization reduction)【Kurshan 1994; Alur et al. 1995】。

 

上图为CEGAR算法描述。算法不断的修正抽象域A,知道证明系统是正确的,或者找到真正的反例为止。

b)        反例和修正

                         i.              反例:一条程序执行路径,其第一个状态为系统的初始状态,最后一个状态为一个错误状态。表明程序可以执行到一个错误状态,也即系统安全的一个反例。

                       ii.              基于语法的修正

1.         一个简单的排出伪反例的方法是查找公式中的不可满足的核心(unsatisfiable core)。有很多方法可以找到这个公式的集合:

a)         用贪心算法找最小不可满足集合,SLAM中用到了该方法【Ball and Rajamani 2002a】;

b)        查询判定的产生过程,找到证明不可满足的那些约束,选择该证明中那些在叶子节点出现的原子公式即可。该方法在BLAST中有实现【Henzinger et al 2002】。

2.         另外一种基于语法的修正方法是计算路径的前驱,即从错误的状态开始,往前计算每一步的状态,并根据计算出的状态中的原子命题进行修正,直至到达初始状态【Namjoshi and Kurshan 2000】。该方法在F-Soft中有应用。

                      iii.              基于插值的修正

基于语法的修正,往往只关注程序表面的一些问题,而没有考虑其内在的联系。而基于插值的方法则不同,【Henzinger et al. 2004】利用Craig插值(Craig Interpolation)来查找能够反映程序内在联系的断言,来验证给定的安全性性质。

                     iv.              基于抽象-修正的模型检测工具

1.         SLAM【Ball and Rajamani 2002b】

2.         BLAST【Beyer et al. 2007a】

3.         MAGIC【Chaki et al. 2003】

4.         F-Soft【Ivancic et al. 2005】

0 0
原创粉丝点击