【課程筆記】南大軟件分析課程7——指針分析基礎(chǔ)(課時9/10)

目錄:

  1. 指針分析規(guī)則

  2. 如何實現(xiàn)指針分析

  3. 指針分析算法

  4. 指針分析如何處理函數(shù)調(diào)用(過程間指針分析)

重點:

理解指針分析的規(guī)則、指針流圖PFG、指針分析算法。

理解指針分析調(diào)用函數(shù)的規(guī)則、過程間指針分析算法、實時調(diào)用圖構(gòu)建。


1.指針分析規(guī)則

首先分析前4種語句:New / Assign / Store / Load。

指針分析的域和相應(yīng)的記法:變量/函數(shù)/對象/實例域/指針,用pt表示程序中的指向關(guān)系(映射)。

7-1-1-標(biāo)記方法.png

規(guī)則:采用推導(dǎo)形式,橫線上面是條件,橫線下面是結(jié)論。

  • New:創(chuàng)建對象,將new T()對應(yīng)的對象oi加入到x的指針集。
  • Assign:將y的指針集加入到x對應(yīng)的指針集。
  • Store:讓oi的field指向oj。
  • Load:Store的反操作。


    7-1-2-規(guī)則.png

2.如何實現(xiàn)指針分析

算法要求:全程序指針分析,要容易理解和實現(xiàn)。

本質(zhì):在指針(變量/域)之間傳遞指向信息。Andersen-style分析(很普遍)——很多solving system把指針分析看作是一種包含關(guān)系,eg,x = y,x包含y。

問題:當(dāng)一個指針的指向集發(fā)生變化,必須更新與它相關(guān)的其他指針。如何表示這種傳遞關(guān)系?PFG。

PFG:用指針流圖PFG來表示指針之間的關(guān)系,PFG是有向圖。

  • Nodes:Pointer = V U (O x F) 節(jié)點n表示一個變量或抽象對象的域。
  • Edges:Pointer X Pointer 邊x -> y 表示指針x指向的對象may會流入指針y。

Edges添加規(guī)則:根據(jù)程序語句 + 對應(yīng)的規(guī)則。

7-2-1-PFG邊規(guī)則.png

示例

7-2-2-PFG示例.png

PTA步驟

  1. 構(gòu)造PFG(根據(jù)以上示例,PFG也受指向關(guān)系影響)
  2. 根據(jù)PFG傳播指向信息

3.指針分析算法

(1)過程內(nèi)PTA算法

7-3-0-PTA算法_過程內(nèi).png

符號

  • S:程序語句的集合。

  • WL:Work list,待合并的指針信息,二元組的集合,<指針n,指向的對象集合pts>。pts將被加入到n的指向集pt(n)中。

  • PFG:指針流圖。

步驟:對每種語句都是基于第1小節(jié)的規(guī)則來實現(xiàn)。

  1. 對S中所有類似New x = new T()的語句,將<x, {oi}>加入到WL。

  2. 對S中所有類似Assign x = y的語句,調(diào)用AddEdge()y -> x加入到PFG,<x, pt(y)>加入到WL(傳播指向信息)。

  3. 遍歷WL,取一個元素<n, pts>,除去pts中與pt(n)重復(fù)的對象得到\Delta,調(diào)用Propagate(n,\Delta)將\Delta加入到pt(n),且取出PFG中所有n指向的邊n->s,將<s, pts>加入到WL(根據(jù)PFG將指向信息傳遞給同名指針)。

  4. 如果n表示一個變量x(x跟Store/Load指令相關(guān)),對\Delta中的每個對象oi。對S中所有類似Store x.f = y的語句,調(diào)用AddEdge()y -> oi.f加入到PFG,<oi.f, pt(y)>加入到WL(傳播指向信息);對S中所有類似Load y = x.f的語句,調(diào)用AddEdge()oi.f -> y加入到PFG,<y, pt(oi.f)>加入到WL(傳播指向信息)。

問題

  1. 為什么要去重?避免冗余,英文叫做Differential propagation差異傳播。

  2. 指針集用什么數(shù)據(jù)結(jié)構(gòu)存儲?混合集 Hibra-set,集合元素小于16個用hash set,大于16個用big-rector 位存儲。

  3. 開源項目有哪些?Soot、WALA、Chord。

(2)示例

1 b = new C(); 
2 a = b;
3 c = new C(); 
4 c.f = a;
5 d = c;
6 c.f = d; 
7 e = d.f;
WL 正處理 PFG 指針集 處理語句 算法語句
1 [<b, {o1}>, <c, {o3}>] 1,3 處理New
2 [<b, {o1}>, <c, {o3}>] a<-b;d<-c; 2,4 處理Assign
3 [<c, {o3}>] <b, {o1}> a<-b;d<-c; pt(b)={o1} while開頭
4 [<c, {o3}>], <a, {o1}>] a<-b;d<-c; Propagate()傳遞,沒有b.f語句
5 [<a, {o1}>] <c, {o3}> a<-b;d<-c; pt(c)={o3} while開頭
6 [<a, {o1}>, <d, {o3}>] a<-b;d<-c; Propagate()傳遞,有c.f語句
7 [<a, {o1}>, <d, {o3}>] a<-b;d<-c;o3.f<-a;o3.f<-d;
7-3-1-PFG.png
4,6 處理Store/Load,添加邊
8 [<d, {o3}>] <a, {o1}> pt(a)={o1}; while開頭
9 [<d, {o3}>,<o3.f, {o1}>] Propagate()傳遞
10 [<o3.f, {o1}>] <d, {o3}> pt(d)={o3} while開頭
11 [<o3.f, {o1}>, <o3.f, {o3}>] Propagate()傳遞,有d.f語句
12 [<o3.f, {o1}>, <o3.f, {o3}>] a<-b;d<-c;o3.f<-a;o3.f<-d;e<-o3.f;
7-3-2-PFG.png
7 處理Load,添加邊
13 [<o3.f, {o3}>] <o3.f, {o1}> pt(o3.f)={o1}; while開頭
14 [<o3.f, {o3}>, <e, {o1}>] Propagate()傳遞
15 [<e, {o1}>] <o3.f, {o3}> pt(o3.f)={o1, o3} while開頭
16 [<e, {o1}>, <e, {o3}>] Propagate()傳遞
17 <e, {o1}>;<e, {o3}>
7-3-3-PFG.png
pt(e)={o1, o3} while開頭

4.指針分析如何處理函數(shù)調(diào)用

構(gòu)造調(diào)用圖技術(shù)對比

  • CHA:基于聲明類型,不精確,引入錯誤的調(diào)用邊和指針關(guān)系。
  • 指針分析:基于pt(a),即a指向的類型,更精確,構(gòu)造更準(zhǔn)的CG并對指針分析有正反饋(所以過程間指針分析和CG構(gòu)造同時進(jìn)行,很復(fù)雜)。
void foo(A a) {   // pt(a) = ???
  ...
    b = a.bar();    // pt(b) = ???  把a的指向分析清楚了,就能確定a.bar()到底調(diào)用哪個對象的bar()函數(shù),那么b的指向也明確了。
    ... 
}

(1)調(diào)用語句規(guī)則

call語句規(guī)則:主要分為4步。

7-4-1-call規(guī)則.png

  1. 找目標(biāo)函數(shù)m:Dispatch(oi, k)——找出pt(x),也即oi類型對象中的k函數(shù)。
  2. receiver object:把x指向的對象(pt(x))傳到m函數(shù)的this變量,即mthis
  3. 傳參數(shù):pt(aj), 1<=j<=n 傳給m函數(shù),即p(mpj), 1<=j<=n。建立PFG邊,a1->mp1,...,an->mpn。
  4. 傳返回值:pt(mret)傳給pt(r)。建立PFG邊,r<-mret。

問題:為什么PFG中不添加x->mthis邊?因為mthis只和自己這個對象相關(guān),而可能有pt(x)={new A, new B, new C},指定對象的x只流向?qū)?yīng)的對象,是無法跨對象傳遞的。

(2)過程間PTA算法

問題:由于指針分析和CG構(gòu)造互相影響,所以每次迭代只分析可達(dá)的函數(shù)和語句。然后不斷發(fā)現(xiàn)和分析新的可達(dá)函數(shù)。

可達(dá)示例

7-4-2-可達(dá)示例.png

算法:黃色背景的代碼是和過程內(nèi)分析不同的地方。

7-4-3-PTA算法_過程間.png

符號

  • mentry:入口main函數(shù)

  • Sm:函數(shù)m中的語句

  • S:可達(dá)語句的集合(就是RM中的語句)

  • RM:可達(dá)函數(shù)的集合

  • CG:調(diào)用圖的邊

步驟:基于調(diào)用規(guī)則來實現(xiàn)。

  1. 首先調(diào)用AddReachable(mentry),將入口函數(shù)mentry的語句加到S中。處理New x = new T()語句,把<x, {oi}>加入到WL;處理Assign x = y語句,調(diào)用AddEdge(y, x)加入邊到PFG。

  2. 跟過程內(nèi)指針分析一樣,遍歷WL,取一個元素<n, pts>,除去pts中與pt(n)重復(fù)的對象得到\Delta,調(diào)用Propagate(n,\Delta)將\Delta加入到pt(n),且取出PFG中所有n指向的邊n->s,將<s, pts>加入到WL(根據(jù)PFG將指向信息傳遞給同名指針)。

  3. 如果n表示一個變量x(x跟Store/Load指令相關(guān)),對\Delta中的每個對象oi。對S中所有類似Store x.f = y的語句,調(diào)用AddEdge()y -> oi.f加入到PFG,<oi.f, pt(y)>加入到WL(傳播指向信息);對S中所有類似Load y = x.f的語句,調(diào)用AddEdge()oi.f -> y加入到PFG,<y, pt(oi.f)>加入到WL(傳播指向信息)。

  4. 最后調(diào)用ProcessCall(x, oi),處理與x相關(guān)的call指令。取出S中類似r = x.k(a1,...,an)的調(diào)用語句L,首先調(diào)用Dispatch(oi, k)解出調(diào)用的目標(biāo)函數(shù)m,把<mthis, {oi}>加入到WL(傳遞接收對象,上下文敏感分析將用到),將L->m這條調(diào)用邊加入到CG;調(diào)用AddReachable(m)將新的語句加入到S,并處理New/Assign語句;調(diào)用AddEdge()將實參->形參、返回值->r邊加入到PFG(傳遞參數(shù)、返回值),并將<形參,pt(實參)>、<r,pt(返回值)>加入到WL。

問題:為什么ProcessCall(x, oi)中,要判斷L->m這條邊是否已經(jīng)加入到CG?因為x可能指向多個對象,就會多次處理L這個調(diào)用指令,可能x中別的對象oj早就已經(jīng)將這條邊加入進(jìn)去了。

(3)示例

1 class A {
2   static void main(){
3       A a = new A();
4       A b = new B();
5       A c = b.foo(a);
6   }
7   A foo(Ax){...}
8 }
9 class B extends A {  
10  A foo(A y) {
11      A r=newA();
12      return r;
13      }
14  }
WL 正處理 PFG 指針集 RM CG 語句 算法語句
1 [] {} {} {} 初始化
2 [] {A.main()} 1,2 AddReachable(mentry)
3 [<a,{o3}>, <b,{o4}>] 3,4
4 [<b,{o4}>] <a,{o3}> pt(a)={o3}; while開頭
5 [] <b,{o4}> pt(b)={o4} while開頭
6 [] 5 ProcessCall(b, o4)
7 [<B.foothis, {o4}>] {5->B.foo(A)} m=Dispatch(o4, foo())=B.foo();添加到調(diào)用圖
8 [<B.foothis, {o4}>, <r, o11>] {A.main(), B.foo()} AddReachable(B.foo());添加到可達(dá)函數(shù)
9 [<B.foothis, {o4}>, <r, o11>, <y, {o3}>] {a->y, r->c}
AddEdge();添加參數(shù)邊、返回值邊
10 [<r, o11>, <y, {o3}>] <B.foothis, {o4}> pt(B.foothis)={o4}; while開頭,B.foothis沒有調(diào)用任何函數(shù)
11 [<y, {o3}>, <c, {o11}>] <r, o11> pt(r)={o11}; while開頭
12 <y, {o3}>, <c, {o11}> pt(y)={o3};pt(c)={o11} while開頭

如果是CHA的話,CG={5->B.foo(A), 5->A.foo(A)},錯誤識別為調(diào)用邊。

結(jié)果

7-4-5-result.png

問題:沒有入口函數(shù)的?如對庫函數(shù)處理,生成調(diào)用庫函數(shù)的程序。


今天喝了點wine,整理的有點魔幻。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容