Lecture3 Data Flow Analysis-Application-笔记

本文参考了该作者的一些图解和见解:https://zhuanlan.zhihu.com/p/131083830

一. 数据流分析概述

在上节,我们学习了CFG,可知静态分析中数据是在CFG中流动的,根据各节点(如BB)的控制流方向来实现Data Flow。那么数据在CFG中怎么流动呢?哪些数据在流动?根据这些问题,就引出了本节内容——数据流分析。

如上图所示,CFG中流动的数据是抽象出来的数据,如+、-、1、T等。而SA的第二部分,则就是Over-approximation,它涉及节点、有向边的内容(第二节中讲到)。

图中Over-approximation对应于may analysis,Under-approximation对应于must analysis。而它们可共称为safe-approximation。也就是对于我们所需要的non-trivial property,该分析必定是safe的(满足我们需求的近似分析),但并不能得到一个精确的答案,这在第一节中有谈到。而关于may、must analys的解释如下所示:

may analysis(Over-approximation):输出的信息可能是正确的。回顾第一节有关sound、Truth、complete的图,可知may analysis对应的分析范围是soundness,也即输出结果尽可能全面,不会出现漏检,但会出现错检。(大部分静态分析沿用may analysis)

must analysis(Under-approximation):输出信息必须正确。可知其对应complete的范围。                                                                                                                                  

此外,在safe-approximation中,另外需要考虑的两个内容就是transfer function与control flow handling,在后续会具体提及。   这一节主要讲解数据流分析的一些经典应用:

  • Reaching Definitions Analysis
  • Live Variables Analysis
  • Available Expressions Analysis

其中RDA和LVA为may analysis,AEA为must analysis;而RDA和AEA又是forward analysis,而LVA是backward analysis。所谓的forward与backward是数据流动方向,由control flow handling所决定。

二. Preliminaries of Data Flow Analysis

 对于3AC的每一条指令可看做图中s1、s2,对于每一条语句都有一个输入、输出状态,相当于中间的s是一个函数,对输入数据作用后输出,而在statement的前和后都称之为一个program point。而对于单一分支上连续的两个节点s1,s2则有OUT[s1] = IN[s2];对于有分支的情况,例如对于分岔处s1之后有分支s2和s3则有OUT[s1] = IN[s2] = IN[s3];而对于分支汇聚处例如s1和s3汇聚到s2则有,其中是一个二元操作符,会在不同的分析中被赋予不同的运算(例如∪,∩...),这里可以理解成前面谈到的分支选择函数∅ 。

 那么具体看一个例子,如下程序,其每一程序点,都对应着一个数据状态(抽象数据),每一个应用都有其对应的Abstraction,第一点中x为正,y还未定义,以此类推可得到每一点的数据值。再看下一句,数据流分析实际上即对于所有的语句s去寻找一个方法来满足一系列直接的safe-approximation限制:

  • 基于语句语义的限制(transfer function)
  • 基于控制流的限制

因此可知,其实transfer function可以看作一种规则,规定好两变量的运算规则。transfer function=语义分析 

也就是要实现数据流分析的步骤:

  1. 实现数据抽象Abstraction;
  2. 选择transfer function,一般定义为fs
  3. 确定控制流的方向,backward或forward。

有了上述的知识,那么就可以定义传递函数transfer function和控制流方向了。而Forward与Backward analysis的区别如下所示:

上述讲的都是单条指令,但实际上CFG上的基本单位是BBs,则将它们顺延到BB中来。IN[B]=IN[s1]即块中首条指令的输入值,而块中的transfer function则为块中所有函数的作用。对于多分支汇聚情况,箭头代表数据流动方向,分别为forward分析与backward分析。对于黄色部分,IN[B]为B的前缀分支的交集;粉色部分中OUT[B]则为B后继节点输入的交集;且他们的传递函数中作用函数反过来。也就是说虽然它们进行数据流分析方向相反,但是它们的OUT与IN仍然与CFG中的单向箭头相对应。

三. Reaching Definitions Analysis

这是一种可达性分析。存在program point p和q,有一定义d给变量v赋值,若存在一条从p->q的路径且在此路径上变量v没重新定义(Killed),则我们可说对于v而言,p->q是可达的。一般情况下,该分析方法可用于检测未定义变量。例如,在CFG入口为程序中每个变量引入一个伪定义(也就是在程序入口处,所有变量设置为T:undefined)。如下面所示,最左边为程序,右边为分析的抽象内容。在程序入口处,对所有变量设置一个伪定义RD(实际上应该为一个二进制向量来存储所有定义在某点的可达性,这里用该写法只为更直观),最右边的USE代表变量是否被使用。当执行到第三条语句时,此时a、b被调用,可是a实际上并没有被赋值,因此我们可判定该变量未定义则调用。

                         OUT[entry] = IN[1]  ---RD{a:T, b:T}     USE(a:0, b:0)
1: int a;                OUT[1] = IN[2]      ---RD{a:T, b:T}     USE(a:0, b:0)
2: double b = 4;         OUT[2] = IN[3]      ---RD{a:T, b:4}     USE(a:0, b:0)
3: print(a + b);         OUT[3]              ---RD{a:T, b:4}     USE(a:1. b:1)

此外,对于分支情况,只要存在一条路径是可达的,那么我们就可以说它满足这个条件。显而易见,RD分析是一种may analysis

已经知道RDA的定义及其应用,那么接下来看一下该如何实现该分析。

 实现步骤如下:

Abstraction:

  1. 寻找程序中所有的变量,将其抽象为定义D1,D2,……,D100;
  2. 将其表示为一个bit vector(0,0,……,0),该vector在程序每一个Program point都存在,表示每一定义(与上面一一对应)在该点的可达性,0表示不可达,1表示可达。在程序入口处,这100个变量皆不可达,因此初始化为100个0;

Safe-approximation:

  1.  Transfer Function:,其中kill特指在块中被用到的定义,只要某个Definition被用到了就kill掉;而gen则表示该块中新定义的变量,它们都会表示为一个二进制向量进行运算。如图:
  2. Control Flow:,这是个forward analysis,此等式表示B的所有前驱结点的输出OUT[P]的并集是B的输入。

到此为止,Reaching Definition Analysis已经设计完毕,在数据抽象、确定Transfer Function以及Control flow后,整个分析则十分简洁明了 。其中,对Transfer Function的设计,一般而言皆为上述的结构、control flow则需要根据前向或者后向分析来确定。当然对于该分析各程序点初始化还没确定,其实际算法结构如下:

上图OUT[entry]=∅,在此应用中应为一个二进制向量,其初始化为全0,因为entry是虚拟的入口,其并无语句,其他变量无法到达,因此全为0表不可达。而排除entry的初始化,是因为此处为经典算法模板,其他分析对entry的初始化不一定为∅。此外,对于该算法迭代,其停止条件是当所有的OUT不再出现变化,程序结束。关于其原理,后续会谈到,其基于不动点原理。

接下来展示一个实际的RDA案例,将上述所讲模块串联起来:

关于示例,只做第一轮迭代。如上图,左上角为抽象数据与bit vector一一对应,0表不可达,1表可达,因此各程序点处的vector初始化为黑色数字。其对应的红色数字为该program point处经过各块之后的新值(由Transfer Function与Control flow决定),在对整个程序完成一次迭代后,由于出现了OUT的变化,因此需要继续进行迭代。当然该样例各位可再听老师讲解,由于个人水平原因,无法用更好的方法来讲该例子,因此讲的比较粗糙。

从以上例子中可以得到一些结论:

  1. 非定义语句的IN和OUT是不变的
  2. 对于任何语句,其gen和kill是不变的,可以认为是一个常量
  3. 当次的IN必定大于等于上一次迭代时候同一个语句(基本块的)IN,所以OUT也必定是大于上一次迭代的OUT,也说此算法是单调(monotonic)的
  4. 算法一定会停下来(算法达到了不动点(fixed point)),原因是定义数量是有限的且因为3得出的算法是单调的结论,想象一个函数单调并值域有限,随着算法随着自变量增大而到达了最大值

关于静态分析的首个应用到此介绍完毕,如果有不合理的地方,请小伙伴们指出来。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值