Falcon
- 1.方法
- 1.1.Basic Rule
- 1.2.改进算法
- 1.3.跨函数分析
- 2.Evaluation
- 2.1.设置
- 2.2.value-flow分析
- 2.3.Thin Slicing
- 2.4.Bug Detection
- 参考文献
这篇工作发表于PLDI 24,提出了一种context- 以semi-path-sensitive的数据依赖分析算法,解决path-sensitive的内存模型中存在的aliasing-path-explosion问题。
1.方法
现有sparse flow-sensitive pointer analysis缺点:
-
1.auxiliary pre-analysis的精度缺失会导致后续分析大量冗余错误pointer-information的传播。
-
2.auxiliary pre-analysis只用到了一个point-to集合,而随后的flow-sensitive分析在处理path-sensitive问题时后point-to集合会出现路径爆炸。
为了解决这些问题作者提出了Falcon,Falcon处理的程序语法如下:
1.1.Basic Rule
作者定义了两个集合 E E E 和 S S S,还定义了对应的查询方式 ∏ φ \prod_{\varphi} ∏φ:
-
E [ p → { . . . } ] E[p \rightarrow \{...\}] E[p→{...}] 表示top-level variable p p p 的指向环境集合,每一个环境为 ( φ , o ) (\varphi, o) (φ,o) 表示一个address-taken object及其对应的路径条件。
-
S [ o → { . . . } ] S[o \rightarrow \{...\}] S[o→{...}],每一个元素 ( π , l , q ) (\pi, l, q) (π,l,q) 表示top-level variable q q q 在语句 l l l 处路径条件为 π \pi π 时赋值给了 o o o (
store
指令)。比如语句 l : ∗ x = q l: *x = q l:∗x=q,该路径条件 π \pi π, x x x 只指向 o o o,那么有 S ( o ) = S ( o ) ∪ ( π , l , q ) S(o) = S(o) \; \cup \; (\pi, l, q) S(o)=S(o)∪(π,l,q)。 -
∏ φ ( S ( o ) ) = { ( π ∧ φ , l , v ) ∣ ( π , l , v ) ∈ S ( o ) } \prod_{\varphi}(S(o)) = \{(\pi \land \varphi, l, v) \; | \; (\pi, l, v) \in S(o)\} ∏φ(S(o))={(π∧φ,l,v)∣(π,l,v)∈S(o)} 表示address-taken variable o o o 在路径条件 φ \varphi φ 下可能的值。这里值用top-level variable表示,也就是存在value-flow v → φ o v \stackrel{\varphi}{\rightarrow} o v→φo。
-
∏ φ ( E ( v ) ) = { ( π ∧ φ , o ) ∣ ( π , o ) ∈ E ( v ) } \prod_{\varphi}(E(v)) = \{(\pi \land \varphi, o)\ \; | \; (\pi, o) \in E(v)\} ∏φ(E(v))={(π∧φ,o) ∣(π,o)∈E(v)} 表示top-level variable 在路径条件 π \pi π 下的指向集合。
-
E ( v ) ⨄ E ′ ( v ′ ) = { ( π ∨ π ′ , o ) ∣ ∀ ( π , o ) ∈ E ( v ) , ∀ ( π ′ , o ) ∈ E ′ ( v ′ ) } E(v) \biguplus E^{'}(v^{'}) = \{(\pi \; \vee \; \pi^{'}, o) \; | \; \forall (\pi, o) \in E(v), \forall(\pi^{'}, o) \in E^{'}(v^{'})\} E(v)⨄E′(v′)={(π∨π′,o)∣∀(π,o)∈E(v),∀(π′,o)∈E′(v′)},表示两个 E E E 集合合并,一个应用的地方就是 Φ \Phi Φ 指令处合并不同的value时,不过关于具体操作paper里说的不是很明确,个人理解是如果 o o o 在两个 E E E 集合处都出现了,那么合并路径条件 π ∨ π ′ \pi \; \vee \; \pi^{'} π∨π′,反之则相当于 π ∨ f a l s e \pi \; \vee \; false π∨false 或者 f a l s e ∨ π ′ false \vee \; \pi^{'} false∨π′。
基础的transfer function如下, E , S ⊢ l , φ : s t m t : E ′ , S ′ E, S \vdash l, \varphi : stmt : E^{′}, S^{′} E,S⊢l,φ:stmt:E′,S′ 表示 E , S E, S E,S 集合经过路径条件 φ \varphi φ 下的语句 l l l 后更新为 E ′ , S ′ E^{′}, S^{′} E′,S′,其中:
-
alloca
指令 p = & a p = \&a p=&a 往 p p p 的 E E E 集合添加 { φ , a l l o c a a } \{\varphi, alloca_a\} {φ,allocaa}。 -
store
指令 ∗ x = q *x = q ∗x=q 更新了 p t s ( x ) pts(x) pts(x) 每个address-taken variable的 S S S 集合。往已有的 S ( o ) S(o) S(o) 集合中添加 ( π , l , q ) (\pi, l, q) (π,l,q) 表示value-flow关系 q → π o q \stackrel{\pi}{\rightarrow} o q→πo。同时只有store
指令会更新 S S S 集合的值,其它只更新 E E E 集合。和SFS类似,如果 ∣ ∏ φ ( E ( x ) ) ∣ = 1 |\prod_{\varphi}(E(x))| = 1 ∣∏φ(E(x))∣=1 也就是 x x x 只指向一个address-taken variable ( π , o ) (\pi, o) (π,o),那么对 o o o 进行strong update,这也是kill功能的实现。 -
Sequencing
和Branching
规则表明Falcon可能通过遍历CFG实现(paper没有明说),由于CFG遍历很费时,为了跳过不必要的CFG node,作者后面提出了一个优化方案。 -
load
,phi
,copy
指令则负责传播指针集合 E E E 的值。其中load
的最为复杂,个人理解是对于 l , φ : p = ∗ y l, \varphi: p = *y l,φ:p=∗y,首先 ∏ φ ( E ( y ) ) = { ( π , o ) , . . . } \prod_\varphi(E(y)) = \{(\pi, o),...\} ∏φ(E(y))={(π,o),...} 查询出满足路径条件的所有指向address-taken variable ( π , o ) (\pi, o) (π,o)(此时存在value-flow o → π p o \stackrel{\pi}{\rightarrow} p o→πp),由于load
指令主要是更新 p p p 的指向集 E ( p ) E(p) E(p),因此需要先查询每个 ( π , o ) (\pi, o) (π,o) 的所有值 ∏ π ( S ( o ) ) \prod_\pi(S(o)) ∏π(S(o))(找出所有的 v → φ o v \stackrel{\varphi}{\rightarrow} o v→φo),这样找到了value-flow v → φ p v \stackrel{\varphi}{\rightarrow} p v→φp,随后合并所有 v v v 的指向集合更新 E ( p ) E(p) E(p)。
value flow的构建规则如下图所示(value-flow只存在于 store --> load
),对于语句 l 1 l_1 l1 处路径条件为 φ 1 \varphi_1 φ1 store
指令 ∗ x = q *x = q ∗x=q,以及语句 l 2 l_2 l2 处路径条件 φ 2 \varphi_2 φ2 的 load
指令 p = ∗ y p = *y p=∗y,查询路径条件 φ 2 \varphi_2 φ2 下 y y y 指向的所有address-taken variable ( π i , o i ) (\pi_i, o_i) (πi,oi),通过 ∏ φ i ( S ( o i ) ) \prod_{\varphi_i}(S(o_i)) ∏φi(S(oi)) 查找 φ i \varphi_i φi 下 o i o_i oi 所有可能的值 ( ( φ i , l 1 , q ) (\varphi_i, l_1, q) (φi,l1,q)),也就是value-flow q → φ i o i q \stackrel{\varphi_i}{\rightarrow} o_i q→φioi,最后合并所有同source value-flow的路径条件,也就是构造value-flow边 q → ∨ φ i p q \stackrel{\vee \varphi_i}{\rightarrow} p q→∨φip。
以下图为例,(b)为传统value-flow构建方法, (c)为Falcon,以处理从 store
∗ x = a *x = a ∗x=a 到 load
d = ∗ x d = *x d=∗x 为例,存在 E ( x ) = { ( φ 1 , o 1 ) , ( ¬ φ 1 , o 2 ) } E(x) = \{(\varphi_1, o_1), (\lnot \varphi_1, o_2)\} E(x)={(φ1,o1),(¬φ1,o2)}, S ( o 1 ) = { φ 1 , l 1 , a } S(o_1) = \{\varphi_1, l_1, a\} S(o1)={φ1,l1,a}, S ( o 2 ) = { ¬ φ 1 , l 2 , a } S(o_2) = \{\lnot \varphi_1, l_2, a\} S(o2)={¬φ1,l2,a}( l 1 , l 2 l_1, l_2 l1,l2是占位符)。处理 d = ∗ x d = *x d=∗x 时query ∏ ¬ φ 2 ( E ( x ) ) \prod_{\lnot \varphi_2}(E(x)) ∏¬φ2(E(x)),发现 φ 1 ∧ ¬ φ 2 \varphi_1 \land \lnot \varphi_2 φ1∧¬φ2 和 ¬ φ 1 ∧ ¬ φ 2 \lnot\varphi_1 \land \lnot \varphi_2 ¬φ1∧¬φ2 都能满足,因此得到 ∏ ¬ φ 2 ( E ( x ) ) = { ( φ 1 , o 1 ) , ( ¬ φ 1 , o 2 ) } \prod_{\lnot \varphi_2}(E(x)) = \{(\varphi_1, o_1), (\lnot \varphi_1, o_2)\} ∏¬φ2(E(x))={(φ1,o1),(¬φ1,o2)},接着分别query ∏ φ 1 ( S ( o 1 ) ) \prod_{\varphi_1}(S(o_1)) ∏φ1(S(o1)) 和 ∏ ¬ φ 1 ( S ( o 2 ) ) \prod_{\lnot \varphi_1}(S(o_2)) ∏¬φ1(S(o2)) 得到 { φ 1 ∧ ¬ φ 2 , l 1 , a } \{\varphi_1 \land \lnot \varphi_2, l_1, a\} {φ1∧¬φ2,l1,a} 和 { ¬ φ 1 ∧ ¬ φ 2 , l 2 , a } \{\lnot \varphi_1 \land \lnot \varphi_2, l_2, a\} {¬φ1∧¬φ2,l2,a}。最后得到value-flow a ⟶ ¬ φ 2 d a \stackrel{\lnot \varphi_2}{\longrightarrow} d a⟶¬φ2d(路径条件简化)。与之相比传统方法的value-flow边就多多了。
1.2.改进算法
不过目前上图的算法还有优化空间,主要原因包括:
-
1.直接在CFG上按上面规则进行传播开销过大。而Sparse分析的pre-analysis构建的SVFG包括太多false def-use。因此也会降低性能。
-
2.大量guard的路径条件需要更新,可能会引起路径爆炸问题,如果严格的对路径条件求解开销过大。
针对问题1作者提出了一个CFG优化方案,主要针对 store
和 load
的遍历。算法如下图所示(Algo1为 store
,Algo2为 load
)。优化的重点是 S S S 集合的访问,首先,store
会修改 S S S 的值而 load
会读取其值。
针对问题1,作者优化了 store
和 load
的遍历规则,其中将 S ( o ) S(o) S(o) 替换为一系列 S l ( o ) S_l(o) Sl(o),表示每个指令 l l l 处address-taken variable o o o 的值。改进后的算法如下图所示,红框为改变处,主要是处理 store
指令时会顺便处理其所有的支配边界,处理 load
时会沿着其直接支配节点回溯。这里需要先进行控制依赖分析。
一个示例如下图所示:
-
在处理
store
语句 l 4 : ∗ x = d l_4: *x = d l4:∗x=d 时,更新完 S l 4 ( a l l o c m ) S_{l_4}(alloc_m) Sl4(allocm) 为 { ( φ , l 4 , d ) } \{(\varphi, l_4, d)\} {(φ,l4,d)} 后,接着找到 l 4 l_4 l4 的支配边界 l 6 l_6 l6,更新 S l 6 ( a l l o c m ) = { φ , l 4 , d } S_{l_6}(alloc_m) = \{\varphi, l_4, d\} Sl6(allocm)={φ,l4,d}。同理,访问 l 5 l_5 l5 也会做对应的更新。 -
在处理
load
语句 l 6 : f = ∗ x l_6: f = *x l6:f=∗x 时, x x x 指向 a l l o c m alloc_m allocm,首先读取 S l 6 ( a l l o c m ) S_{l_6}(alloc_m) Sl6(allocm) 的值,获的 ( φ , l 4 , d ) (\varphi, l_4, d) (φ,l4,d),表示value-flow d ⟶ φ f d \stackrel{\varphi}{\longrightarrow} f d⟶φf;随后,追溯到 l 6 l_6 l6 的直接支配节点 l 3 l_3 l3,读取 ( t r u e , l 3 , c ) (true, l_3, c) (true,l3,c) 的值后,根据Algo2第9行 φ = π ∧ σ ∧ β \varphi = \pi \land \sigma \land \beta φ=π∧σ∧β 和第14行 σ = ¬ π ∧ β \sigma = \lnot \pi \land \beta σ=¬π∧β 的规则更新为 ( ¬ φ , l 3 , c ) (\lnot \varphi, l_3, c) (¬φ,l3,c),表示value-flow c ⟶ ¬ φ f c \stackrel{\lnot \varphi}{\longrightarrow} f c⟶¬φf( c c c 会在 φ \varphi φ 下被kill掉)。根据这两个value-flow更新 E ( f ) E(f) E(f)。
针对问题2,作者将程序的表达式都抽象为bool skeleton,比如将 x < 2
, x >=2
, y = 100/2
抽象为布尔谓词 p p p, ¬ p \lnot p ¬p, q q q。其次,Falcon并不使用功能齐全的SAT求解器,而是采用几种线性时间的半决策程序,如unit-propagation,用于识别“简单”的不可满足约束,并执行轻量级的逻辑简化,如消除重言式。在实验中,作者发现约70%的路径条件是可满足的。对于其余的路径条件,其中80%是简单约束,可以通过半决策程序解决。value-flow边的修剪和合并例子如下图所示。
1.3.跨函数分析
与SVF不同,作者依然采用采用一个按照call-graph的拓扑序自底向上先构造每个函数的Value-Flow Graph然后以summary-based方法先构造整体value-flow graph,也就是先独立分析每个函数生成summary,然后按需获取summary进行进一步分析。
通常summary需要注意的是side-effect,对于下图(a)所示代码片段,在对 foo
函数生成摘要时,通常会假设参数 y
指向一个address-taken variable o
。按照作者的设定,foo
初始处有 E ( y ) = { ( t r u e , o ) } E(y) = \{(true, o)\} E(y)={(true,o)},分析完整个程序后, S ( o ) = { ( φ , l 2 , c ) , ( ¬ φ , l 3 , a ) } S(o) = \{(\varphi, l_2, c), (\lnot \varphi, l_3, a)\} S(o)={(φ,l2,c),(¬φ,l3,a)}。由于 y y y 为 foo
和其 caller
的接口,因此 foo
的side-effect只涉及到 y y y,因此 E ( y ) E(y) E(y) 和 S ( o ) S(o) S(o) 就是需要的side-effect。
summary最终会在分析call语句的时候用到,这里 qux
和 bar
函数都调用了 foo
,同时 qux
和 bar
的参数和 bar
一致,假设在 qux
的调用处, E ( x ) = { ( φ 1 ′ , o 1 ) , ( φ 2 ′ , o 2 ) , ( φ 3 ′ , o 3 ) } E(x) = \{(\varphi^{'}_1, o_1), (\varphi^{'}_2, o_2), (\varphi^{'}_3, o_3)\} E(x)={(φ1′,o1),(φ2′,o2),(φ3′,o3)},那么将summary展开后就有了 S ( o 1 ) = { ( φ ∧ φ 1 ′ , l 2 , c ) , ( ¬ φ ∧ φ 1 ′ , l 3 , a ) } S(o_1) = \{(\varphi \land \varphi^{'}_1, l_2, c), (\lnot \varphi \land \varphi^{'}_1, l_3, a)\} S(o1)={(φ∧φ1′,l2,c),(¬φ∧φ1′,l3,a)}, S ( o 2 ) = { ( φ ∧ φ 2 ′ , l 2 , c ) , ( ¬ φ ∧ φ 2 ′ , l 3 , a ) } S(o_2) = \{(\varphi \land \varphi^{'}_2, l_2, c), (\lnot \varphi \land \varphi^{'}_2, l_3, a)\} S(o2)={(φ∧φ2′,l2,c),(¬φ∧φ2′,l3,a)}, S ( o 3 ) = { ( φ ∧ φ 3 ′ , l 2 , c ) , ( ¬ φ ∧ φ 3 ′ , l 3 , a ) } S(o_3) = \{(\varphi \land \varphi^{'}_3, l_2, c), (\lnot \varphi \land \varphi^{'}_3, l_3, a)\} S(o3)={(φ∧φ3′,l2,c),(¬φ∧φ3′,l3,a)}。如果调用有多层,那么摘要数量可能指数爆炸。
针对这个问题,作者引入了一个辅助变量 R R R,上面 foo
的摘要变成 E ( y ) = { ( t r u e , o ) } E(y) = \{(true, o)\} E(y)={(true,o)}, S ( o ) = { ( t r u e , l 4 , R ) } S(o) = \{(true, l_4, R)\} S(o)={(true,l4,R)}, R = { ( φ , l 2 , c ) , ( ¬ φ , l 3 , a ) } R = \{(\varphi, l_2, c), (\lnot \varphi, l_3, a)\} R={(φ,l2,c),(¬φ,l3,a)}。具体的构造方法如下图所示,在添加辅助变量的同时,对于 void
返回类型,算法还会添加一个额外返回值,示例如上图(b)所示
假设分析 foo
时
-
独立分析完
foo
后有: E ( y ) = { ( t r u e , o ) } E(y) = \{(true, o)\} E(y)={(true,o)}, S ( o ) = { ( φ , l 2 , c ) , ( ¬ φ , l 3 , a ) } S(o) = \{(\varphi, l_2, c), (\lnot \varphi, l_3, a)\} S(o)={(φ,l2,c),(¬φ,l3,a)}, E ( c ) = { t r u e , j } E(c) = \{true, j\} E(c)={true,j}, E ( a ) = { t r u e , k } E(a) = \{true, k\} E(a)={true,k}。(此时 a a a, c c c 均为一阶指针,对其指向集进行指针分析意义不大,故忽略 k , j k, j k,j 的指向集)。value-flow edge包括: ( c = & j ) → ( ∗ y = c ) (c = \&j) \rightarrow (*y = c) (c=&j)→(∗y=c)、 ( a = & k ) → ( ∗ y = a ) (a = \&k) \rightarrow (*y = a) (a=&k)→(∗y=a)、 ( ∗ y = c ) ⟶ φ ( R = ∗ y ) (*y = c) \stackrel{\varphi}{\longrightarrow} (R = *y) (∗y=c)⟶φ(R=∗y)、 ( ∗ y = a ) ⟶ ¬ φ ( R = ∗ y ) (*y = a) \stackrel{\lnot \varphi}{\longrightarrow} (R = *y) (∗y=a)⟶¬φ(R=∗y)。 -
用Algo3分析后得到 E ( y ) = { t r u e , o y } E(y) = \{true, o_y\} E(y)={true,oy}( o y o_y oy 为新建object), S ( o y ) = { ( t r u e , , R ) } S(o_y) = \{(true, \; , R)\} S(oy)={(true,,R)}, E ( R ) = { ( φ , j ) , ( ¬ φ , k ) } E(R) = \{(\varphi, j), (\lnot \varphi, k)\} E(R)={(φ,j),(¬φ,k)}。
利用 f f f 的summary分析caller语句 l , φ : r = f ( u ) l, \varphi: r = f(u) l,φ:r=f(u) 的规则如下,以caller qux
中的 foo(x)
为例,假设 E ( x ) = { ( φ 1 , o 1 ) } E(x) = \{(\varphi_1, o_1)\} E(x)={(φ1,o1)}
-
(1).在callee的summary中替换形参( y y y)和返回值( R R R),构造中间变量 E f ′ ( y ) = { ( φ 1 , o 1 ) } E^{'}_f(y) = \{(\varphi_1, o_1)\} Ef′(y)={(φ1,o1)}, S f ′ ( o 1 ) = { ( φ 1 , , R ) } S^{'}_f(o_1) = \{(\varphi_1, , R)\} Sf′(o1)={(φ1,,R)}, E ( R ) = { ( φ 1 ∧ φ , j ) , ( φ 1 ∧ ¬ φ , k ) } E(R) = \{(\varphi_1 \land \varphi, j), (\varphi_1 \land \lnot \varphi, k)\} E(R)={(φ1∧φ,j),(φ1∧¬φ,k)}。
-
(2).合并后为 E ′ ( x ) = { ( φ 1 , o 1 ) } E^{'}(x) = \{(\varphi_1, o_1)\} E′(x)={(φ1,o1)}, S f ′ ( o 1 ) = { ( φ 1 , , L 1 ) } S^{'}_f(o_1) = \{(\varphi_1, , L_1)\} Sf′(o1)={(φ1,,L1)}, E ( L 1 ) = { ( φ 1 ∧ φ , j ) , ( φ 1 ∧ ¬ φ , k ) } E(L_1) = \{(\varphi_1 \land \varphi, j), (\varphi_1 \land \lnot \varphi, k)\} E(L1)={(φ1∧φ,j),(φ1∧¬φ,k)}。
在上述示例中,qux
的call语句后面还添加了 store
语句 *x = L1
,接着 foo(x)
分析,那么更新了 S ( o 1 ) S(o_1) S(o1) 的值为 { ( φ 1 , l ′ , L 1 ) } \{(\varphi_1, l^{'}, L_1)\} {(φ1,l′,L1)}。这里 l ′ l^{'} l′ 为 store
语句。
在call分析完后,value-flow中会添加summary edge,主要从callee的return value对应的 store
(可能是已有的也可能是新添加的)连接到caller后面的 load
处,在上上张图示例(b)中,foo
结尾插入 R = *y
以及 return R
,以及在 qux
和 bar
的caller处添加返回值 L1
(还有 L2
)以及后面跟着 store
语句 *x = L1
(还有 *z = L2
),那么会在新添加的callee的 load
和caller的 store
中间添加一个summary edge。(这里感觉首先需要对IR进行语义等价转换,可能方法和Pinpoint一样)。
2.Evaluation
2.1.设置
下游任务包括:(1).Thin Slicing for Program Understanding、(2).Value-flow Bug Finding: 主要是use-after-free。
baseline包括:
-
(a).指针分析的比较对比:(1).SVF (主要是SVF实现的Andersen算法)、(2).SFS(稀疏值流分析)、(3).DSA (unionfication-based, flow-insensitive, context-sensitive算法,实现采用sea-dsa)
-
(b).slicing与SUPA-FSCS进行对比
-
©.bug finding与CRED、clang-static-analyzer (CSA) 进行对比。
benchmark采用了6个SPEC INT 2010程序以及10个开源程序。
2.2.value-flow分析
value-flow分析主要对比时间开销,结果如下表和下图所示,SVF、SFS、DSA为baseline,Falcon(PI)和Falcon(SAT)为消融实验,分别表示采用path-insensitive和采用全量SAT进行约束求解的开销。可以看到Falcon的时间开销相比其它方法有着巨大优势。
2.3.Thin Slicing
为了生成真实的slicing query,作者使用typestate分析提得到的bug report。从对应程序位置的问题变量开始backward分析,结果可以帮助开发人员理解这些报告。主要比较每个slicing query的处理时间(排除value-flow graph的时间),precison和recall。后两者有两位作者进行了人工验证。
时间开销:Falcon对每个slicing query的处理时间少于240ms。总的来说,它比SUPA-FSCS快302倍,平均加速54倍。这一性能提升归因于Falcon生成的value-flow graph比SUPA-FSCS更紧凑。
Precision:Falcon生成的slicing平均大小比SVF、SFS、DSA和SUPA-FSCS分别小5.5倍、1.9倍、2.6倍和1.3倍。表示过滤了很多错误的语句。
Recall:Falcon假设函数参数之间不存在别名,这一不sound的假设对超过90%的query没有影响,经过手动检查结果得到了验证。两项先前的研究也表明,真实世界的C/C++程序中的函数参数往往具有很少的别名关系。
2.4.Bug Detection
use-after-free bug检测的结果如下图所示,分别对比了时间开销和误报率。可以看出,Falcon在大多数大规模程序中超越了CRED和CSA,平均速度提升分别达到10.3倍和1620.8倍(以工具完成的项目为基准)。尽管表中未显示,但作者观察到,如果允许10个线程并发分析,Falcon可以在两小时内完成每个程序的检查。CRED、CSA和Falcon的虚假正例率分别为40.0%、33.3%和27.8%。我们注意到,CSA报告的警告明显少于CRED和Falcon,部分原因是频繁超时和在跨编译单元分析路径时能力有限。Falcon符合工业界对30%误报率的常见要求。
参考文献
[1].Yao P, Zhou J, Xiao X, et al. Falcon: A Fused Approach to Path-Sensitive Sparse Data Dependence Analysis[J]. Proceedings of the ACM on Programming Languages, 2024, 8(PLDI): 567-592.