指针分析是一个非常复杂的工作,这些工作很多方向,比如是否是上下文敏感分析或上下文不敏感分析,显然,这难易度是不一样地。比如下图。对于同一段代码,敏感性分析如蓝色,不敏感分析如红色。
相比之下,不敏感分析不在乎语句的顺序,比如2,4两个语句换一下位置,得到的结果还是一样的,同时也不要求结果是否精确。
不敏感分析特点:安全。
即确保召回那个唯一正确的值就好,而不管精确不精确,是不是多了。
下面我们要讨论的就是不敏感分析。所以有些语句我们是不会管的,比如:
即,我们只管那些赋值的,和指针相关的语句。从而将此工作得到了大大简化。
Anderson’s pointer analysis
这个指针分析的算法很有名,是分析C语言的,但是思想都是通用的,下面开始介绍。
基础
解释:我们暂时先不看第一列和第三列,其他的应该很好理解。
a=&b,a=&c
,那么有pts(a)={loc(b),loc(c)}
。约束图
现在我们要做一些前期工作,并且要开始看上面那个表的第一列和第三列。举例来说,如果有代码:
p = &a;
q = &b;
*p = q;
r = &c;
s = p;
t = *p;
*s = r;
我们按照上面表的第3列翻译成下面,叫做约束:
p ⊇ {a}, q ⊇ {b}, *p ⊇ q, r ⊇ {c}, s ⊇ p, t ⊇ *p, *s ⊇ r
我们可以开始根据上面的表格创建初始约束图,其中基本(base)约束和(simple)约束是创建初始约束图的基础。初始约束图的创建分为如下三步:
可以得到如下图:
解释:正如名字,上面只是约束图,而且只是一个初始约束图,图中的边也并不是指针的指向关系,而是约束关系。拿上图的边edge(p,s)为例,其表示p所指向的,s都将指向。
实战
下面用一个例子来进行实战整个Anderson算法。
int i, j, k;
int *a = &i;
int *b = &k;
a = &j;
int *p = &a;
int *q = &b;
p = q;
int *c = *q;
可以得到如下的约束:
a ⊇ {i, j}, b ⊇ {k}, p ⊇ {a}, q ⊇ {b}, p ⊇ q, c ⊇ *q
从而得到如下初始约束图:
上面的work_queue工作队列就是下面伪代码中的W。伪代码如下:
(我们已经完成了1,2步了)。
开始执行循环,从队列中取出a。
由于找不到关于a的复杂约束,复杂约束是什么?除了简单约束和基本约束就是复杂约束,具体可以参照开头的那个表格。
由于找不到a出发的边,所以此循环结束,如下。
取出b,
找不到关于b的复杂约束
找不到b出发的边
此循环结束,如下。
取出p,
找不到复杂约束
找不到p出发的边。
此循环结束,如下。
取出q,
找到复杂约束,c ⊇ *q
。q的指向有b,从而加入边edge(b,c)。而且加入b到工作队列中。
找到q出发的边edge(q,p),所以pts§={a,b},由于pts§改变了,增加了一个元素,所以p再次加入到工作队列中。
此循环结束。
取出b,
没有复杂约束
找到b出发的边,所以pts©={k},由于pts©改变了,所以c加入到工作队列中。
此循环结束。
取出p,
没有复杂约束
没有从p出发的边
此循环结束。
取出c,
找到复杂约束c ⊇ *q
,但是复杂约束的形式和算法中的不一样,所以for循环结束。
找不到c出发的边
此循环结束。
由于工作队列为空,此算法结束。
将旁边的那些集合比如{i,j}统统连上,即edge(a,i),edge(a,j)…。就变成了我们最终要的指针指向关系了。
这样我们就完成了指针分析。