“相反,若程序为 ,包含分析保留pt(p)=${a}$、pt(q)=${b}$,只有pt(r)=${a,b}$。Steensgaard合一分析会用更粗的目标等价类换取更低成本;这组例子可以精确…”
形式陈述
Steensgaard分析用存储形状的等价类近似可能地址,允许把多个目标合成一个代表,以获得近线性的求解成本。它与Andersen包含分析一样通常是流不敏感、上下文不敏感;差别在于目标关系的表示与合并方式。
本页选原算法的无函数值、无字段指针片段。每个变量位置x有位置代表
注意 x=y传播的是存储内容的目标形状,不是断言变量x和y位于同一个地址。具体含义仍以可变存储为基准。
合并与条件合并
join(a,b)合并两个代表;若两者形状分别为
cjoin(dst,src)遵循输入到输出方向:若src已有非底形状,就执行join;若src仍为
对规范化指针语句,核心规则为:
x=&y:x=y:x=*y:若 尚无形状,赋予 ;否则令其为 ,执行*x=y:若 尚无形状,赋予 ;否则令其为 ,执行
分配站点h提供一个独立位置标签及初始形状,令新指针目标与
直觉
Andersen允许p只指a、q只指b,而r指a或b。Steensgaard要求r只有一个目标代表,所以把a和b装进同一个位置类;此后任何指向该类的指针都可能指其中任一成员。
这会把一条新别名传播到原本较精确的其他指针,但不需要反复维护任意大的目标集合。等价类只能合并、不能拆开,有限代表数量给出很低的更新成本。
例子与边界
一个合并为何影响三个指针
执行分析以下语句,顺序只用于展示求解过程,不作为流敏感杀死信息:
p = &a
q = &b
r = p
r = q
前两句令
于是
相比之下,包含分析只让r得到两目标,p仍只有a、q仍只有b。额外目标来自等价类合并,不是程序真的把q的值写进了p。
变量p和q自己的位置代表 u=&p、v=&q,不应仅凭p、q目标相同就断言u、v都指向同一变量位置。目标层与容器层必须区分。
条件合并保留了什么
先遇到 x=y,此时 x=&a,x获得目标a,但y仍无指针事实;原版不会仅因这次单向赋值就把a反向灌给y。
若后来出现 y=&b,
如果直接为每条赋值无条件join,第一种程序就会让y也指a。这依然可以是可靠的更粗分析,却不再是这里给出的原版条件合并结果。
自指针不是类型错误
语句 x=&x 使
这里的“类型”是存储形状,不是源语言的Int、Bool等静态类型。只用ref一种形状构造器时,合并的职责是保守覆盖地址关系,不是发现通常意义上的类型不匹配。
推论与应用
一次赋值只产生常数个代表及合并约束,整个规范化程序产生
线性空间描述的是共享等价类图。若对每个变量显式打印其可能目标列表,许多变量可以指向同一个大类,输出总长仍可能为
可靠性建立在存储形状对具体地址边的覆盖上。join只扩大类而不删地址,解引用规则确保目标单元的内容形状与读写源相容;条件合并在源端没有信息时延迟,但一旦有信息就执行全部必要合并,因此不会永久漏掉约束。
用于大程序的初筛时,较粗结果可能仍足以证明很多地址互不相关。若关键告警恰由大等价类造成,可以只对相关区域改用包含分析或更细上下文,而不是假定一种分析在所有精度/成本维度都占优。
参考资料
- Bjarne Steensgaard, “Points-to Analysis in Almost Linear Time”, POPL, 1996, 32–41,§§3–5、Figures 5–6:存储形状、条件join、并查集求解与复杂度
- Anders Møller and Michael I. Schwartzbach, Static Program Analysis,2026年8月版,§11.4:合一式表示;该教材明确省略原算法条件合并,本页保留此差别