循环不变式
使用循环头位置的循环不变式,来替代表达循环实际执行的效果,即表达循环的执行对程序变量的值的影响。 循环头位置的循环不变式意味着,不论循环执行多少次,对程序变量的值所造成的影响,都会在循环不变式所约束的范围内。
分离逻辑
p=1和q=2,p、q可以指向同一区域,涉及指针操作时,仍然保证霍尔逻辑推理的正确性。引入Frame约束来描述内存操作,操作p的时候q不会变。
两种解决方案:Frame约束;或者不用Frame约束,而采取分离逻辑,因为分离逻辑与的定义是指向不同内存区。
值函数 x = 10 即原封不动的值函数 s(x)=10
堆函数 h(x) = 10,在地址x处存储的值为10
x↦y, 等价于h(s(x)) = s(y),h(x) = y
我们会试图证明s,h |= P,表示在给定的s,h下,分离逻辑公式P是有效的。 通常,我们会省略s,h,简记为公式P。
正是因为分离与(*)操作要求子堆不相交,我们在进行分离逻辑推理时,不再需要显示地添加Frame约束。
其它运算也是分离逻辑独有,比如分离蕴含
有界程序验证
上近似用于证明,而下近似用于证伪(找错,Bug Finding)
对于程序中执行次数未定的循环(无界循环,Unbounded Loop),尝试将其展开固定次数进行分析。 所以有界程序验证是一种下近似验证算法。在实际生产环境中,有界程序验证方法几乎不会用来证明带有未定次数循环的程序的正确性。
因为一个程序有错,那么就肯定存在至少一条确定的错误路径,而在这条错误路径上,循环的执行次数肯定是有限的
无界循环(Unbounded Loop)指不能从代码中轻易得出其执行次数的循环。 比如for(i = 0; i < 10; i++) { … }这样的循环就不算无限。while循环默认为无界循环。
学习最弱前置条件计算时有如下等价:
while(b) {c} <=> if(b) {c; while(b) {c}}
ITE(f, g, h)函数:if f then g else h
SSA语句的守卫指该语句被执行到时所要满足的条件。
求解带有全称量词的逻辑公式效率是比较低的。可以使用对偶性来消除全称量词。
k归纳法
扩展了有界程序验证算法。 起初,我们使用不变式来上近似代替循环。 在前一篇所介绍的有界程序验证中,使用固定次数展开来下近似代替循环。 将归纳原理与程序验证中的循环处理建立联系,我们可以获得新的思路。
k=1就是普通数学归纳法
k归纳法使用了P(x)更多的信息,使得证明过程简化
可以使用有界程序验证,展开循环k-1次,完成Base Case(1)的证明。
符号分析
变量取值符号化,基本操作、基本语句的过程、结果符号化
反复进行迭代计算,直到各个位置程序变量的取值类型不再发生改变,即达到了迭代的不动点(Fix-point)。 我们就求出了程序变量的取值在程序各个位置的上近似。
符号分析只能证一些数值范围
以上符号分析的过程,可以被抽象为一个更一般的算法。 我们称之为抽象解释(Abstract Interpretation)框架。 目前,大部分的静态分析算法都可以基于抽象解释框架进行描述。抽象解释的数学基础是格论(Lattice Theory)
区间分析
一种简单的不变式自动生成算法——区间分析(Interval Analysis)
值分析算法关注程序中变量的取值随着程序控制流(Control Flow)的变化
抽象后继算子定义了如何计算当前抽象状态在经过某种程序中的操作/运算后,所得到的后继抽象状态。状态合并算子用于计算控制流交汇处的抽象状态。
区间抽象抽象域是[a,b],抽象后继算子类似最值运算和取交集
符号分析取值类型仅能沿着这个图上的边从下往上变化。迭代停止的条件是各个位置的抽象状态不再变化(至此到达不动点)。抽象迭代的次数一定有上界
区间分析,其迭代计算在理论上不一定终止。( 在抽象解释的迭代过程中,计算所得的抽象状态不断向不动点逼近,但这个过程可能不终止。)为了解决这个问题,抽象解释框架引入了加宽算子(Widening Operator)。加宽算子能够加速这个过程,使得计算所得的抽象状态越过不动点,在后续的向下迭代的过程中达到不动点而终止。
区间分析案例
由于区间分析的结果一般强于符号分析,所以我们希望在这个例子中,能够通过区间分析证明更多的性质。试图证明循环中不会发生数组的上/下越界。下越界可以通过> / < 0来证明,上越界需要更精确的信息
该例子需要11轮迭代,如果i < 9999,则需要10000轮迭代是低效的,所以引入加宽算子,比如区间边界连续单调变化三次后,对其进行加宽。
直到各个位置的区间不再发生变化,迭代停止。至此,计算出了程序各个位置上程序变量i的值的区间上近似。 这实际上对应了各个位置上i的值的区间不变式。 使用区间分析方法,自动生成了该循环不变式。 相比于符号分析,区间分析得出了更加强的结果。除了生成区间不变式之外,我们还可以在抽象解释的框架下,定义其他的抽象域,以自动生成更加复杂的不变式。
本篇我们也讨论了抽象解释算法框架的一个非常重要的问题,即「为什么迭代能终止」。 注意到迭代终止的要求是各个位置程序变量的抽象状态不再发生改变,即达到不动点(Fix-point)。对于有限的抽象域(如符号抽象域)而言,单调函数的重复迭代最终会达到其不动点。 而对于无限的抽象域(如区间抽象域),抽象解释借助于加宽算子保证迭代的终止性。
程序终止性验证
程序终止性:程序中循环的终止性,即不存在死循环
使用方法:秩函数
根据秩函数的性质可以求得秩函数