【南大软件分析-学习笔记】Lecture 5-Data Flow Analysis-Foundation(下)

5. Relate Iterative Algorithm to Fixed-Point Theorem

5.1 Relatation

在上节课我们证明了不动点理论,但是还遗留了三个最开始提出的问题没有解决:

  1. 这个算法一定能终止吗,也就是说它一定有不动点、有解吗?
  2. 如果一定有不动点的话,那么它会只有一个不动点还是有多个不动点,如果是有多个不动点的话,如何保证我们得到的是最好(最精确)的?
  3. 这个算法将会在什么时候达到一个不动点呢?

想要回答这三个问题,我们需要将迭代算法和我们上节课所学习的有关格的知识,也就是不动点理论结合起来。

再来看一下我们之前给出的例子,我们在上节课所证明的不动点定理是针对单个偏序集和单个传递函数而言的,对应到 CFG 中就需要针对单个节点或者单个 BB 来说。那么,如果想把不动点理论应用到真实的数据流分析算法中,就需要把所有程序节点的分析结果合成一个向量 \(v\),把“一轮更新”看成一个函数 F 。这样,反复更新直到结果不变,就是再求 F 的不动点。

\[v=(v_1, v_2,...,v_k) \in L^k \]

不难分析,向量 \(v\) 是一个乘积格,根据乘积格的性质:一系列完全格组成的乘积格也是完全(complete)的,并且是有限(finite)的,再结合 不动点理论成立的三个条件:完全格、函数 F 有限且单调 ,所以接下来我们只需要证明“一轮更新”对应的整体函数 F 是单调的。

5.2 How to prove Function F is Monotonic

下面来证明函数 F 是单调的。

我们已经知道函数 F 包含两类操作:

  1. 每个节点内部的传递函数 \(f_i\) : \(L\rightarrow L\);
  2. 多条控制流汇合时的 join / meet (\(\sqcup\) / \(\sqcap\)):\(L \times ... \times L \rightarrow L\)。

只要这两个操作都单调,把它们组合起来得到的函数 F 自然也是单调的。

在上一节证明单调性的时候,我们默认函数 f 是单调的,在实际中主要的函数 f 是 Gen 和 Kill,这些在设计时就决定的是单调的了,否则没法使用,比如说在 bit vector 中 0000 中如果某个字节变成了1,就不会变回0了,这样一来传递函数部分就是单调的了,接下来只需要证明 join / meet 操作也是单调的,F 就是单调的了,下面我们以 join 操作为例,来证明操作符操作也是单调的,证明过程是这样的:

\[\forall x,y,z \in L,x \preceq y,\text{we want to prove: } x \sqcup z \preceq y \sqcup z \]

  1. 由 \(\sqcup\) (最小上界)的定义可知,\(y \preceq y \sqcup z\);
  2. 那么由传递性可以得到,\(x \preceq y \sqcup z\);
  3. 因此,\(y \sqcup z\) 是 \(x\) 的上界,也是 \(z\) 的上界;
  4. 又 \(x \sqcup z\) 是 \(x\) 和 \(z\) 的最小上界,因此,\(x \sqcup z \preceq y \sqcup z\) 得证。

这样,join 操作的单调性就得证了,同样的方法不难证明 meet 操作也是单调的,因此不动点理论可以用于上面所描述的迭代算法。

这样的话,根据不动点理论,Q1 和 Q2 显而易见是正确的,那么 Q3 呢?

Q3 是指在最坏情况下,需要经过多少次迭代才能达到不动点。我们假设每次迭代只在一个节点 OUT 对应的格上走了一步,格的高度是 h,CFG 上有 k 个节点,那么最多需要 \(i = h * k\) 次迭代才能达到不动点。

6. May and Must Analysis, a Lattice View

接下来尝试从格的角度来看 May & Must Analysis,以这个幂集为例,假设这个幂集表示 CFG 中各节点的 OUT 对应的格,图中最上方是\(\top\),最下方是 \(\bot\),为了更加直观的分析,将其映射到右侧椭圆中,这个椭圆实际上是一个 product lattice,may analysis 和must analysis 都是一个从 unsafe 往 safe 的过程。

6.1 May Analysis

May Analysis 的目的是纠错,因此初始化在 \(\bot\) ,此时分析结果是无错误,因此这肯定是一个 unsafe 的结果;而在 \(\top\) 处,说明分析出来所有点都是错误的,这个分析结果是 safe 的,但是太浪费了,没有实际意义。因此我们的目的就是找到一个平衡点,假设我们找到了 truth 点,那么就可以以此为界将区域划分为 unsafe 和safe 两块,交界点为 truth。在之前的学习中我们也说了,在实际算法的设计中我们几乎是不可能找到 truth 的算法的,也就是 sound & complete 的算法,我们只能找到一系列的不动点,这一系列的不动点都是 safe的,但自下而上,越往上精度越低,所以对 may analysis 来说最接近 truth 的点就是最小不动点。

6.2 Must Analysis

同样的方法我们再来看 Must Analysis,Must Analysis 的目的是删除优化,因此初始化在 \(\top\),此时分析结果为所有语句都可以删除,这肯定是 unsafe 的,分析思路同 may analysis 一致。

7. MOP and Distributivity

7.1 Meet-Over-All-Paths Solution (MOP)

下面介绍另一种解法,与我们之前使用的算法不同,我们以前使用的算法是在运行过程中沿着数据流反复迭代的,而 MOP 是找出从开头到结尾所有路径,分别进行传递函数计算,最后将算完的所有路径进行 \(\sqcup\) / \(\sqcap\),公式如下:

\[\mathrm{MOP}[S_i] = \mathop{\sqcap\ \sqcup_{\text{A path } P \text{ from Entry to } S_i}} F_P(\mathrm{OUT}[\mathrm{Entry}]) \]

7.2 OURS vs. MOP

那么两种算法的精度是怎么样的呢?对于下图所示的一个简单的 CFG,分别使用两种方法得到:

\[\mathrm{IN}[S_4] = f_{S_3}\big(f_{S_1}(\mathrm{OUT}[\mathrm{Entry}]) \sqcup f_{S_2}(\mathrm{OUT}[\mathrm{Entry}])\big) \]

\[\mathrm{MOP}[S_4] = f_{S_3}\big(f_{S_1}(\mathrm{OUT}[\mathrm{Entry}])\big) \sqcup f_{S_3}\big(f_{S_2}(\mathrm{OUT}[\mathrm{Entry}])\big) \]

为了方便分析,我们将相同的部分提出来,进一步的得到:

\[OURS =F(x \sqcup y) \]

\[MOP = F(x)\sqcup F(y) \]

下面开始证明:

  1. 由 \(\sqcup\) 的定义可知:\(x\preceq x \sqcup y\) 并且 \(y\preceq x \sqcup y\) ;
  2. F 是单调的,那么 \(F(x)\preceq F(x\sqcup y)\) 并且 \(F(y) \preceq F(x \sqcup y)\) ;
  3. 所以 \(F(x\sqcup y)\) 是 \(F(x)\) 和 \(F(y)\) 的上界,又 \(F(x) \sqcup F(y)\) 是 \(F(x)\) 和 \(F(y)\) 的最小上界;
  4. 因此 \(F(x)\sqcup F(y) \preceq F(x\sqcup y)\),即 \(MOP \preceq OURS\)。

结合我们在第六节说的,对于 may analysis 来说,越往下精度越高,因此迭代算法的精度要小于MOP;同样的可以证明对于 must analysis 来说 \(OURS \preceq MOP\),must analysis 越往上精度越高,迭代算法的精度仍然要小于MOP。

不过当函数 F 满足 distributivity 时,也就是 \(F(x \sqcup y)=F(x)\sqcup F(y)\),这时候二者精度是一致的,我们在前两节课所介绍的三种方法都是可分配的,下面介绍一种不可分配的方法。

8. Constant Propagation

待会更

9. Worklist Algorithm

posted @ 2026-10-16 19:05  乙烯酷  阅读(45)  评论(0)    收藏  举报