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

0. 前言

前面的两节课介绍了三种常见的数据流分析方法,接下来的两节课将介绍数据流分析的理论部分,废话不多说,直接开始了。(拔智齿肿成猪头了,太痛苦了)

1. Iterative Algorithm, Another View

首先我们先再来看一下迭代算法的通用伪代码模板,这里以 May & Forward Analysis 为例:

我们在上一节课的学习中已经知道,对于每个 BB,我们会使用一个 bit vectors 来表示它的输入 IN 和输出 OUT,那么,换一个角度,对于一个有 k 个节点的 CFG 来说,我们可以认为迭代算法在每轮迭代中实际更新的是每个节点 n 的 OUT[n],假设在该数据流分析中的值域为 V ,那么我可以定义一个 k-tuple 来表示每轮迭代更新后的结果:

\[(OUT[n_1], OUT[n_2], OUT[n_3], ... ,OUT[n_k]) \]

它是集合 \((V_1 \times V_2 \times V_3 \times...\times V_k )\) 中的一个元素,这个集合记作 \(V_K\)。

与此同时,每一轮迭代可以看作从 \(V_k\) 中的一个元素到一个新元素的映射,映射过程就是 transfer functions 和 control-flow handling,可以将这个过程抽象为一个函数 \(F:V_k \rightarrow V_k\) 。

我们用一个简单的例子来简单的表示一下这个迭代过程:

\[\begin{array}{l} \text{init} \rightarrow (\bot,\bot,\dots,\bot)=X_0 \\ \text{iter}_1 \rightarrow (V_1^1,V_2^1,\dots,V_k^1)=X_1=F(X_0) \\ \text{iter}_2 \rightarrow (V_1^2,V_2^2,\dots,V_k^2)=X_2=F(X_1) \\ \quad\vdots \\ \text{iter}_i \rightarrow (V_1^i,V_2^i,\dots,V_k^i)=X_i=F(X_{i-1}) \\ \text{iter}_{i+1} \rightarrow (V_1^{i+1},V_2^{i+1},\dots,V_k^{i+1})=X_{i+1}=F(X_i) \end{array} \]

算法会不断根据函数 F 输出一系列的 k-tuple,当某一轮的输出 k-tuple 与上一轮的 k-tuple 一致时,迭代停止,这与我们之前分析的实际情况也一致,这样一来,我们就可以得到关系:

\[X_i=X_{i+1}=F(X_i) \]

也就是说:

\[X_i =F(X_i) \]

我们将这种情况成为上述迭代算法达到了一个不动点(fixed point) X 。

我们也可以将找到的这个不动点 X 称作为数据流分析找到一个了一个可行解,那么接下来针对这个可行解,我们又引出以下三个问题:

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

为了回答以上三个问题,我们需要学习一些离散数学中的知识。

2. Some math foundation

2.1 Partial Order

定义: 当一个集合满足偏序关系时,我们将此集合定义为偏序集(poset),用\((P,\preceq)\)表示,其中 \(\preceq\) 满足以下三个特性:

  1. Reflexivity(自反性):\(\ \forall x \in P,\, x \preceq x \\\)
  2. Antisymmetry(反对称性):$\ \forall x,y \in P,, x \preceq y \land y \preceq x \implies x = y \ $
  3. Transitivity(传递性):\(\ \forall x,y,z \in P,\, x \preceq y \land y \preceq z \implies x \preceq z\)

下面结合四个典型的例子来更好的理解相关概念:

  1. \((S,\preceq)\) 是一个poset,其中 S 表示整数集,\(\preceq\) 表示小于等于。

  2. \((S,\preceq)\) 是一个poset,其中 S 表示整数集,\(\preceq\) 表示小于。

  3. \((S,\preceq)\) 是一个poset,其中 S 是一个字符串集合,\(\preceq\) 表示子串关系。

  4. \((S,\preceq)\) 是一个poset,其中 S 是一个幂集,\(\preceq\) 表示子集关系。

结合偏序关系的三个特性,不难发现 example1,3,4 满足要求,是偏序集,而 example2不满足自反性,不是偏序集。

2.2 Upper and Lower Bounds

定义: 给定一个偏序集 \((P, \preceq)\),集合 \(S\) 是 \(P\) 的一个子集,我们称 \(u \in P\) 是 \(S\) 的一个上界(upper bound),当且仅当对于\(\forall x \in S\),\(x\preceq u\);同样的,\(l\in P\) 是 \(S\) 的一个下界(lower bound),当且仅当对于 \(\forall x \in S,l \preceq x\)。

以 example 4 的幂集为例,整个幂集表示集合 \(P\),绿色部分表示集合 \(S\),根据以上定义,我们可以得到 {a, b, c} 是集合 \(S\) 的一个上界,{ } 是集合 \(S\) 的一个下界。

进一步的,对于一个集合 \(S\) 来说,我们还可以定义最小上界(least upper bound,读作 lub or join),记作 \(\sqcup S\) ,对于 \(S\) 的每一个上界 \(u\) 来说,有 \(\sqcup S \preceq u\);同样的,还可以定义最大下界(greast lower bound,读作 glb or meet),记作 \(\sqcap S\),对于 S 的每一个下界 \(l\) ,有 \(l \preceq \sqcap S\)。通常的,如果集合 \(S\) 只有两个元素 a 和 b(S = {a, b}),难么还可以将 \(\sqcup S\) 写作 \(a \sqcup b\)(the join of a and b),同样的,也可以将 \(\sqcap S\) 写作 \(a \sqcap b\)(the meet of a and b)。

还是以上面的幂集为例,我们将集合 \(S\) 重新用绿色部分划分,如下所示:

重新划分集合 S 后根据以上定义不难发现,{a, b} 和 {a, b, c} 都是集合 S 的上界,而 {a, b, c} 是集合 S 的最小上界;而 { } 既是集合 S 的下界,又是最大下界。

关于上下界还有两个简单的特性:

  1. 不是所以的 poset 都有 lub 或 glb,比如下图中的集合 P 就没有 glb;

  2. 如果一个 poset 有 lub 或者 glb,那么它一定是唯一的;这个结合使用反证法和传递性不难得证。

2.3 Lattice

定义:对于一个偏序集 \((P, \preceq)\) 来说,如果 \(\forall a,b \in P\),\(a\sqcup b\) 和 \(a \sqcap b\) 都存在的话,那么可以将这个偏序集成为一个格,换句话说,偏序集 \(P\) 中的任意两个元素组成的子集都具有 glb 和 lub。

我们再看一下之前给出的四个例子,根据格的定义,不难得出,example 1 和 example 3 所表示的集合是一个格。

2.3.1 Semilattice

定义: 对于一个偏序集 \((P, \preceq)\) 来说,如果 \(\forall a,b \in P\),只存在 \(a\sqcup b\) 的话,就将这个偏序集称为 join semilattice;如果只存在 \(a\sqcap b\) 的话,就将这个偏序集称为 meet semilattice。

2.3.2 Complete Lattice

定义: 对于一个偏序集 \((P, \preceq)\) 来说,如果 \(\forall S \in P\),\(\sqcup S\) 和 \(\sqcap S\) 都存在的话,那么可以将这个偏序集成为一个完全格,换句话说,偏序集 \(P\) 中的任意子集 S 都具有 glb 和 lub。

example 4 中所展示的幂集就是一个典型的完全格。

对于每一个完全格 \((P,\preceq)\) 来说,它都有一个最大的元素 \(\top = \sqcup P\),称作 top;一个最小的元素 \(\bot = \sqcap P\),称作 bottom。

每一个有限格(finite lattice)都是完全格,但反过来,完全格不一定是有限的,比如[0 , 1]范围上的实数格。

2.3.3 Product Lattice

定义:给定一系列的格 \(L_1 = (P_1, \preceq),L_2=(P_2, \preceq),...,L_n=(P_n,\preceq)\),如果对于所有 \(i\),\((P_i,\preceq_i)\) 都有 \(\sqcup_i\) 和 \(\sqcap_i\),那么我们可以定义乘积格 \(L^n=(P,\preceq)\)如下:

\[\begin{array}{m} P = P_1 \times \dots \times P_n \\ (x_1,\dots,x_n) \preceq (y_1,\dots,y_n) \iff (x_1 \preceq y_1) \land \dots \land (x_n \preceq y_n) \\ (x_1,\dots,x_n) \sqcup (y_1,\dots,y_n) = (x_1 \sqcup_1 y_1,\dots,x_n \sqcup_n y_n) \\ (x_1,\dots,x_n) \sqcap (y_1,\dots,y_n) = (x_1 \sqcap_1 y_1,\dots,x_n \sqcap_n y_n) \end{array} \]

不难得到:

  • 乘积格也是格;
  • 完全格构成的乘积格也是完全格。

3. Data Flow Analysis Framework via Lattice

在学习了格的相关知识后,我们再来看基于格的数据流分析,基于格的数据流分析基本框架为:(D, L, F),它由三部分组成:

  • D:direction,数据集传输的方向,前向 or 反向;
  • L:由值域 V 和一个 meet \(\sqcap\) 或 join \(\sqcup\) 操作符组成的格;
  • F:从 V 到 V 的一系列传递函数。

数据流分析可以看做是在格的数值域上,迭代地使用传递函数和 meet / join 操作符。

4. Monotonicity & Fixed Point Theorem

4.1 Monotonicity

定义: 函数 \(f:L \rightarrow L(L 是格)\) 是单调的,当且仅当 \(\forall x,y \in L,x \preceq y \rightarrow f(x)\preceq f(y)\)。

4.2 Fixed Point Theorem

给定一个完全格 \((L,\preceq)\),如果 \(f:L \rightarrow L\) 是单调且有限的,那么:

  1. f 的最小不动点(least fixed point)可以通过以下方式得到:不断迭代计算 \(f(\bot),f(f(\bot)),...,f^k(\bot)\),直到到达一个不动点;
  2. f 的最大不动点(greast fixed point)可以通过类似的方式方式得到:不断迭代计算 \(f(\top),f(f(\top)),...,f^k(\top)\),直到到达一个不动点;

那么该如何证明不动点理论呢,我们分两步来证明,先证明不动点存在,再证明我们找到的不动点是最小的,以证明最小不动点为例,证明过程如下:

  1. 先证明不动点的存在

    • 前面我们已经知道 \(\bot = \sqcap L\) 是格上的最小元素,所以 \(\bot \preceq f(\bot)\),并且我们 f 是单调的,不断应用 \(x \preceq y \rightarrow f(x)\preceq f(y)\) 的映射关系,我们可以得到一个上升链:

      \[\bot \preceq f(\bot) \preceq f^2(\bot) \preceq ... \preceq f^H(\bot) \]

    • 又因为 L 是有限的,假设其高度为 H (H 是格上 bot 到 top 的最长路径),那么这个数列就应该是有限的,它的值域为:

    \[\bot,f(\bot),f^2(\bot),....,f^H(\bot) \]

    并且这个数列的上限就应该为 \(f^H(\bot)\);

    • 既然数列是有限的,那么根据鸽巢理论,必然存在 \(k < j \leq H + 1\) ,使得 \(f^k(\bot) = f^j(\bot)\),又因为 f 是单调的,那么\(f^k(\bot) \preceq...\preceq f^j(\bot)\),若令相同的值为a,中间的值为b,中间任意段应该满足\(a\preceq b \preceq a\),根据格的反对称性,首尾一致,那么中间所有的值也都一致,即 \(f^{fix}=f^k(\bot)=...=f^j(\bot)\),因此不动点存在。
  2. 再证明该不动点是最小不动点

    采用数学归纳法来证明该不动点是最小不动点,即对于任意不动点x,都有 \(f^{fix} \preceq x\) 。

    • 假设除了不动点 \(f^{fix}\) 外还有一个不动点 \(x\),使得 \(x = f(x)\),由于 \(\bot\) 是最小元素,根据函数的单调性,可以得到 \(f(\bot)\preceq f(x)\);
    • 像上面一样,对两边使用多次函数的单调性,可以得到 \(f^i(\bot) \preceq f^i(x)\);
    • 同样的,在上面我们已经证明,当迭代稳定后,\(f^{fix} = f^i(\bot) \preceq f^i(x) = x\),即 \(f^{fix} \preceq x\) ,最小不动点得证明。
posted @ 2026-10-15 20:16  乙烯酷  阅读(14)  评论(0)    收藏  举报