SVFTools的约束图 C o n s t r a i n t G r a p h ConstraintGraph ConstraintGraph简称
CG
,是用来做指针分析的。根据四条规则,在PAG的基础上建立。在这个过程中,PAG是不变的,而CG则是有可能改变的。
指针分析的Andersen规则与SVF中的规则
使用集合符号,令 p p p是一个指针,则 p t s ( p ) pts(p) pts(p)是 p p p所有可能指向的对象的集合。例如源代码
int o1, o2, *p;
p = &o1; p = &o2;
则
p
t
s
(
p
)
=
{
o
1
,
o
2
}
pts(p)=\{o1, o2\}
pts(p)={o1,o2}
Andersen指针规则一共有4条,两条基本规则,两条扩展规则。
序号 | 规则 | 说明 |
---|---|---|
1 | x = & o , 则 o ∈ p t s ( x ) x={\&}o,则\ o\in pts(x) x=&o,则 o∈pts(x) | 如果有 x = & o x={\&}o x=&o语句,则将 o o o加到 p t s ( x ) pts(x) pts(x)中 |
2 | x = y , 则 p t s ( x ) ⊇ p t s ( y ) x=y,则\ pts(x)\supseteq pts(y) x=y,则 pts(x)⊇pts(y) | 如果有 x = y x=y x=y语句,则将 p t s ( y ) pts(y) pts(y)加到 p t s ( x ) pts(x) pts(x)中 |
3 | x = ∗ y , 则 p t s ( x ) ⊇ p t s ( o ) , 其 中 o ∈ p t s ( y ) x=*y,则\ pts(x)\supseteq pts(o),其中o\in pts(y) x=∗y,则 pts(x)⊇pts(o),其中o∈pts(y) | 如果有 x = ∗ y x=*y x=∗y语句,则将 p t s ( y ) pts(y) pts(y)中所有元素的 p t s pts pts集合加到 p t s ( x ) pts(x) pts(x)中 |
4 | ∗ x = y , 则 p t s ( o ) ⊇ p t s ( y ) , 其 中 o ∈ p t s ( x ) *x=y,则\ pts(o)\supseteq pts(y),其中o\in pts(x) ∗x=y,则 pts(o)⊇pts(y),其中o∈pts(x) | 如果有 ∗ x = y *x=y ∗x=y语句,则将 p t s ( y ) pts(y) pts(y)加到 p t s ( x ) pts(x) pts(x)中的每一个元素的 p t s pts pts集合中 |
有SVFTools操作的LLVMIR指令,并且将指令转变为了SVF的图数据结构,因此SVF中有不同的规则表现形式,其规则是
序号 | 规则 | 说明 |
---|---|---|
1 | s ⟶ a d d r t , 则 s ∈ p t s ( t ) s\stackrel{addr}{\longrightarrow}t,则s\in pts(t) s⟶addrt,则s∈pts(t) | 如果s到t有一条addr边,则将s加到pts(t)中 |
2 | s ⟶ c o p y t , 则 p t s ( s ) ∪ p t s ( t ) s\stackrel{copy}{\longrightarrow}t,则pts(s)\cup pts(t) s⟶copyt,则pts(s)∪pts(t) | 若s到t有一条copy边,则将pts(s)合并到pts(t) |
3 | s ⟶ l o a d t , 则 u ⟶ c o p y t , 其 中 u ∈ p t s ( s ) s\stackrel{load}{\longrightarrow}t,则u\stackrel{copy}{\longrightarrow}t,其中u\in pts(s) s⟶loadt,则u⟶copyt,其中u∈pts(s) | 如果s到t有一条load边,则pts(s)中的所有节点到dst加一条copy边 |
4 | s ⟶ s t o r e t , 则 s ⟶ c o p y u , 其 中 u ∈ p t s ( t ) s\stackrel{store}{\longrightarrow}t,则s\stackrel{copy}{\longrightarrow}u,其中u\in pts(t) s⟶storet,则s⟶copyu,其中u∈pts(t) | 如果s到t有一条store边,则s到pts(t)中的所有节点加一条copy边 |
5 | s ⟶ g e p t , 则 p t s ( u . m ) ∪ p t s ( t ) , 其 中 u ∈ p t s ( s ) , m 是 u 的 成 员 s\stackrel{gep}{\longrightarrow}t,则pts(u.m)\cup pts(t),其中u\in pts(s),m是u的成员 s⟶gept,则pts(u.m)∪pts(t),其中u∈pts(s),m是u的成员 | 若s到t有一条取成员边,则将所有的pts(u.m)合并到pts(t) |
其中第一条规则可以称为基本规则,后面是扩展规则。其中第3条规则相当于 t = ∗ s t=*s t=∗s,第4条规则相当于 ∗ t = s *t=s ∗t=s。
第零个例子
源代码、IR代码和PAG图分别如下
void f(){
int o;
}
define dso_local void @f() #0 !dbg !7 {
entry:
%o = alloca i32, align 4
call void @llvm.dbg.declare(metadata i32* %o, metadata !10, metadata !DIExpression()), !dbg !12
ret void, !dbg !13
}
SVFTools的PointTo分析结果如下
(4, f): (5, f (base object))
(11, llvm.dbg.declare): (12, llvm.dbg.declare (base object))
(7, o): (8, o (base object))
前两行是函数的,暂时忽略。这里有意义的结果就是第三行节点7的 p t s pts pts集合,其中只包含节点8。这是显然的。
第一个例子
源代码
void f(){
int o1, o2, *x, **p;
x = &o1;
x = &o2;
p = &x;
}
define dso_local void @f() #0 !dbg !7 {
entry:
%o1 = alloca i32, align 4
%o2 = alloca i32, align 4
%x = alloca i32*, align 8
%p = alloca i32**, align 8
store i32* %o1, i32** %x, align 8, !dbg !21
store i32* %o2, i32** %x, align 8, !dbg !22
store i32** %x, i32*** %p, align 8, !dbg !23
ret void, !dbg !24
}
PAG与CG的主要部分
其PTA结果为
(9, o2): (10, o2 (base object))
(11, x): (12, x (base object))
(7, o1): (8, o1 (base object))
(13, p): (14, p (base object))
(14, p (base object)): (12, x (base object))
(12, x (base object)): (8, o1 (base object)) (10, o2 (base object))
由第1条规则可以得到前面4行。节点7到11有一条store边,所以7到pts(11)中的所有节点都要加一条copy边。而pts(11)={12},所以7到12加一条copy边。其他也是一样。
第二个例子
源代码
void f(){
int o1,o2,*x,*y;
y = &o1;
x = y;
y = &o2;
}
define dso_local void @f() #0 !dbg !7 {
entry:
%o1 = alloca i32, align 4
%o2 = alloca i32, align 4
%x = alloca i32*, align 8
%y = alloca i32*, align 8
store i32* %o1, i32** %y, align 8, !dbg !20
%0 = load i32*, i32** %y, align 8, !dbg !21
store i32* %0, i32** %x, align 8, !dbg !22
store i32* %o2, i32** %y, align 8, !dbg !23
ret void, !dbg !24
}
PAG图和CG图
PTA的结果是
(11, x): (12, x (base object))
(7, o1): (8, o1 (base object))
(9, o2): (10, o2 (base object))
(13, y): (14, y (base object))
(14, y (base object)): (8, o1 (base object)) (10, o2 (base object))
(12, x (base object)): (8, o1 (base object)) (10, o2 (base object))
对照PAG图,可以看到前4行就是由基础规则生成的。而第5行的结果则是根据第3条store规则生成。再来看最后一行有关x的pts,节点20到节点11有一条store边,所以节点20到pts(11)中的每一个节点都有一条copy边,也就是20到12加一条copy边。再看节点13到节点20的load边,所以 所有pts(13)中的节点到节点20有一条copy边,也就是14到20加一条copy边。最后考虑copy边,由于copy边的存在,pts(14)要合并到pts(20),而pts(20)要合并到pts(12),所以pts(12)的最后结果也是 { o 1 , o 2 } \{o1, o2\} {o1,o2}。
第三个例子
源代码
void f(){
int o1,o2,o3,o4,*p1,*p2,**y,*x;
x = *y;
y = &p1;
y = &p2;
p1 = &o1;
p2 = &o2;
p1 = &o3;
p2 = &o4;
}
IR代码
define dso_local void @f() #0 !dbg !7 {
entry:
%o1 = alloca i32, align 4
%o2 = alloca i32, align 4
%o3 = alloca i32, align 4
%o4 = alloca i32, align 4
%p1 = alloca i32*, align 8
%p2 = alloca i32*, align 8
%y = alloca i32**, align 8
%x = alloca i32*, align 8
%0 = load i32**, i32*** %y, align 8, !dbg !29
%1 = load i32*, i32** %0, align 8, !dbg !30
store i32* %1, i32** %x, align 8, !dbg !31
store i32** %p1, i32*** %y, align 8, !dbg !32
store i32** %p2, i32*** %y, align 8, !dbg !33
store i32* %o1, i32** %p1, align 8, !dbg !34
store i32* %o2, i32** %p2, align 8, !dbg !35
store i32* %o3, i32** %p1, align 8, !dbg !36
store i32* %o4, i32** %p2, align 8, !dbg !37
ret void, !dbg !38
}
PAG图
PAG图上可以很容易看到o1
和o3
指向p1
,o2
和o4
指向p2
,而p1
和p2
指向y
。y
l
o
a
d
load
load两次,产生两个临时变量%0和%1,并且%1最后
s
t
o
r
e
store
store到x
。
CG图
PTA结果
(15, p1): (16, p1 (base object))
(13, o4): (14, o4 (base object))
(9, o2): (10, o2 (base object))
(7, o1): (8, o1 (base object))
(11, o3): (12, o3 (base object))
(17, p2): (18, p2 (base object))
(19, y): (20, y (base object))
(21, x): (22, x (base object))
(18, p2 (base object)): (10, o2 (base object)) (14, o4 (base object))
(16, p1 (base object)): (8, o1 (base object)) (12, o3 (base object))
(20, y (base object)): (16, p1 (base object)) (18, p2 (base object))
(22, x (base object)): (8, o1 (base object)) (10, o2 (base object)) (12, o3 (base object)) (14, o4 (base object))
其中,前8行由基础的addr规则生成。第9、10、11行的生成之前也有阐述,即利用store生成。关键是最后一行x的pts集合的生成过程。首先是19到31有一条load边,所以pts(19)的所有节点也就是20到31有一条copy边。既然是copy边,就要把pts(20)合并到pts(31)。而pts(20)是pts(15)和pts(17)的并集,也就是
{
16
,
18
}
\{16, 18\}
{16,18},分别代表p1和p2。
然后31到32有一条load边,也就是要把pts(31)的所有节点即16和18加一条到32的copy边,由于加了copy边,所以要把pts(16)和pts(18)合并到pts(32),所以pts(32)实际上等于
{
o
1
,
o
2
,
o
3
,
o
4
}
\{o1,o2,o3,o4\}
{o1,o2,o3,o4}。最后32到21有一条load边,所以32到22加一条copy边,所以最终得到了pts(22)。
第四个例子
源代码
void f(){
int o1,o2,*y,**x,*p1,*p2;
y = &o1;
y = &o2;
*x = y;
x = &p1;
x = &p2;
}
define dso_local void @f() #0 !dbg !7 {
entry:
%o1 = alloca i32, align 4
%o2 = alloca i32, align 4
%y = alloca i32*, align 8
%x = alloca i32**, align 8
%p1 = alloca i32*, align 8
%p2 = alloca i32*, align 8
store i32* %o1, i32** %y, align 8, !dbg !25
store i32* %o2, i32** %y, align 8, !dbg !26
%0 = load i32*, i32** %y, align 8, !dbg !27
%1 = load i32**, i32*** %x, align 8, !dbg !28
store i32* %0, i32** %1, align 8, !dbg !29
store i32** %p1, i32*** %x, align 8, !dbg !30
store i32** %p2, i32*** %x, align 8, !dbg !31
ret void, !dbg !32
}
其PTA的结果是
(15, p1): (16, p1 (base object))
(13, x): (14, x (base object))
(11, y): (12, y (base object))
(9, o2): (10, o2 (base object))
(7, o1): (8, o1 (base object))
(17, p2): (18, p2 (base object))
(14, x (base object)): (16, p1 (base object)) (18, p2 (base object))
(12, y (base object)): (8, o1 (base object)) (10, o2 (base object))
(27, ): (8, o1 (base object)) (10, o2 (base object))
(28, ): (16, p1 (base object)) (18, p2 (base object))
(18, p2 (base object)): (8, o1 (base object)) (10, o2 (base object))
(16, p1 (base object)): (8, o1 (base object)) (10, o2 (base object))
前六行是基本的 a d d r addr addr边生成PTA。第7、8行也是很简单的原则,生成的PTA结果。主要要考虑源代码 ∗ x = y *x=y ∗x=y对PTA的影响。13到28有一条 l o a d load load边,所以 p t s ( 13 ) pts(13) pts(13)中的所有点也就是14到28有一条 c o p y copy copy边,所以 p t s ( 28 ) = { p 1 , p 2 } pts(28)=\{p1, p2\} pts(28)={p1,p2}。再考虑到27到28有一条 s t o r e store store边,所以27到p1和p2也就是16和18各有一条 c o p y copy copy边,于是pts(p1)和pts(P2)均为 { o 1 , o 2 } \{o1, o2\} {o1,o2}。
第五个例子
struct _t{
int *p;
};
void f(){
int o1, o2;
struct _t a, b, *x;
x = &a;
x = &b;
x->p = &o1;
x->p = &o2;
}
(15, x): (16, x (base object))
(13, b): (14, b (base object))
(11, a): (12, a (base object))
(9, o2): (10, o2 (base object))
(7, o1): (8, o1 (base object))
(25, p): (12, a (base object)) (14, b (base object))
(24, ): (12, a (base object)) (14, b (base object))
(27, ): (12, a (base object)) (14, b (base object))
(28, p1): (12, a (base object)) (14, b (base object))
(12, a (base object)): (8, o1 (base object)) (10, o2 (base object))
(14, b (base object)): (8, o1 (base object)) (10, o2 (base object))
(16, x (base object)): (12, a (base object)) (14, b (base object))