基于soot的过程内数据流分析

程序静态分析

程序静态分析(program static analysis)是指在不运行代码的方式下,通过词法分析、语法分析、控制流、数据流分析等技术对程序代码进行扫描,验证代码是否满足规范性、安全性、可靠性、可维护性等指标的一种代码分析技术。(百度百科

静态分析中的xxx-sensitive的一些理解:

(此内容来自知乎

xxx-sensitive是指静态分析中用于降低误报(false positive)的技术。存在flow-、path-、context-。

flow-insensitive:是把statements当作一个集合来看的,各个statement之间没有顺序,所以control flow statement(if、while)可以直接删除;flow-sensitive是说要关注statements之间的先后顺序。

path-insensitive:if、while静态分析时不知道动态的执行路线(path),所以一般会把它们不同的分支的数据流集merge起来。而path-sensitive则针对不同的路径的数据集不会merge,而是分别进行分析;

context-insensitve:只关心function之间的数据传递(参数、返回值、side-effect)而忽略了同一函数在不同call side下不同的context,即忽略了call stack。将call site和return当作goto,并添加一些赋值语句,这样造成的情况是,第一个call site处正常,第二个call site时返回值可能出现两个。

静态分析时,无论是分析源代码还是目标代码,分析的对象(方法、语句、变量)都只有一份:同一个方法我们只会写一个方法体(方法体里的语句也就只有一份)。同一个变量只会声明一次。然后动态运行程序的时候:

一个方法可能会被调用N次,每次调用的上下文可以不一样,不同上下文中这个方法里的变量的值会不同;一个方法里,一个变量的不同位置的值也会不一样;一个方法里同一个位置的变量的值在程序执行不同路径时也不一样。写的方法、语句、变量在动态运行时仿佛有了“分身”,每个分身都有自己的值。静态分析的时候对于同一个对象只能看到一个实体,如果直接分析,一个变量所有“分身”的相关属性会全部合并,并且一个变量的属性合并了,会影响其他变量的分析结果。

静态分析为得到准确的结果,就得为分析的对象模拟动态运行时的分身。

xxx-sensitive就是在静态分析时,按照xxx给程序里的对象(模拟动态运行)创建“分身”(或者说按照xxx区分分析对象):按照上下文区分叫作context-sensitive;按照位置区分叫作flow-sensitive;按照路径区分叫作path-sensitive。区分之后就可以减少false positive。

数据流分析

(此内容来自龙书)

数据流分析:指的是一组用来获取有关数据如何沿着程序执行路径(control-flow graph)流动的相关信息的技术。

在所有的数据流分析应用中,我们都会把每个程序点和一个数据流(data-flow value)关联起来。这个值是在该点可能观察到的所有程序状态的集合的抽象表示。所有可能的数据流值的集合称为这个数据流应用的域(domain)。

我们把每个语句s之前和之后的数据流值分别记为IN[s]和OUT[s]。数据流问题(data-flow problem)就是要对一组约束求解。这组约束对所有的语句s限定了IN[s]和OUT[s]之间的关系。约束分为两种:基于语句语义(传递函数)的约束和基于控制流的约束。

数据流分析一般分为:intra-procedural analysis和inter-proceduralanalysis,在上篇Phase中提到,jtp pack和wjtp pack可以分别被用来实现自定义的数据流分析

实现数据流分析前需要搞清楚的问题

数据流的方向(前向、后向);交汇运算采用交集还是并集(当path-insenstitive时);传递函数;数据流集合的初始化。

采用soot框架实现过程内数据流分析

(此部分内容参考点击打开链接

1.      过程内数据流分析

过程内数据流分析(intra-proceduraldata-flow analysis)指在一个单独方法的控制流图上操作。在soot中的控制流图为UnitGraph。UnitGraph中节点表示statements,如果在控制流上一个表示source node流向target node,那么这两个结点存在边(edge)。

数据流分析都与unitgraph每个节点上的两个元素有关,这两个集合被称为:in-set和out-set。这些集合会被初始化,然后沿着语句节点传播,指导一个定点抵达才停止。

最后,你要做的就是检查每个句子的前后的flow set。通过设计的数据流分析,你的flow sets应该会直接告诉你所需要的信息。

2.      Forward、backward orbranched(解决数据流的方向问题)?

在soot中FlowAnalysis存在三种不同类型的方法:

ForwardFlowAnalysis:这个分析以UnitGraph的entrystatement作为开始并开始传播;

BackwardsFlowAnalysis:这个分析以UnitGraph的exit node(s)作为分析并且向后开始传播(当然可以将UnitGraph转换产生inverseGraph,然后再使用ForwardFlowAnalysis进行分析);

ForwardBranchedFlowAnalysis:这个分析本质上也是Forward分析,但是它允许你在不同分支处传递不同的flow sets。例如:如果传播到如if(p!=null)语句处,当“p is not null”时,传播进入“then”分支,当“p is null”时传播进入“else”分支(Forward、backward分析都在分支处会将分析结果merge)。

3.      实现过程间数据流分析的关键方法

Constructor

必须实现一个携带DirectedGraph作为参数的构造函数,并且将该参数传递给super constructor。然后,在构造函数结束时调用doAnalysis(),doAnalysis()将真正执行数据流分析。而在调用super constructor和doAnalysis之间,可以自定义数据分析结构。

<span style="font-size:14px;">public MyAnalysis(DirectedGraph graph) { //构造函数
	super(graph);
	// TODO Auto-generated constructor stub
	emptySet = new ArraySparseSet();
	doAnalysis();//执行fixed-point
}</span>

newInitialFlow()和entryInitialFlow()(数据流集合的初始化问题

newInitialFlow()方法返回一个对象,这个对象被赋值给每个语句的in-set和out-set集合,除过UnitGraph的第一个句子的in-set集合(如果你实现的是backwards分析,则是一个exit statement语句)。第一个句子的in-set集合由entryInitialFlow()初始化。

<span style="font-size:14px;">@Override
protected Object newInitialFlow() {
	// TODO Auto-generated method stub
	return emptySet.emptySet();
}

@Override
protected Object entryInitialFlow() {
	// TODO Auto-generated method stub
	return emptySet.emptySet();
}</span>

copy(..)

copy(..)方法携带两个参数,一个source和一个target。它仅仅实现将source中的元素拷贝到target中。

<span style="font-size:14px;">@Override
protected void copy(Object source, Object dest) {
	// TODO Auto-generated method stub
	FlowSet srcSet = (FlowSet)source,
	destSet = (FlowSet)dest;
	srcSet.copy(destSet);
}</span>

merge(..)(数据流的交汇运算问题

merge(..)方法被用来在control-flow的合并点处合并数据流集,例如:在句子(if/then/else)分支的结束点。与copy(..)不同的是,它携带了三个参数,一个参数是来自左边分支的out-set,一个参数是来自右边分支的out-set,另外一个参数是两个参数merge后的集合,这个集合将是合并点的下一个句子的in-set集合。

注:merge(..)本质上指的是控制流的交汇运算,一般根据待分析的具体问题来决定采用并集还是交集。

<span style="font-size:14px;">@Override
protected void merge(Object in1, Object in2, Object out) {
	// TODO Auto-generated method stub
	FlowSet inSet1 = (FlowSet)in1,
	inSet2 = (FlowSet)in2,
	outSet = (FlowSet)out;
	//inSet1.union(inSet2, outSet);
	inSet1.intersection(inSet2, outSet);
}</span>

flowThrough(..)(数据流的传递函数问题

flowThrough(..)方法是真正执行流函数,它有三个参数:in-set、被处理的节点(一般指的就是句子Unit)、out-set。这个方法的实现内容完全取决于你的分析。

注:flowThrough()本质上就是一个传递函数。在一个语句之前和之后的数据流值受该语句的语义的约束。比如,假设我们的数据流分析涉及确定各个程序点上各变量的常量值。如果变量a在执行语句b=a之前的值为v,那么在该语句之后a和b的值都是v。一个赋值语句之前和之后的数据流值的关系被称为传递函数。针对前向分析和后向分析,传递函数有两种风格。

<span style="font-size:14px;">@Override
protected void flowThrough(Object in, Object d, Object out) {
	// TODO Auto-generated method stub
	FlowSet inSet = (FlowSet)in,
	outSet = (FlowSet)out;
	Unit u = (Unit) d;
	kill(inSet,u,outSet);
	gen(outSet,u);
}

private void kill(FlowSet inSet, Unit u, FlowSet outSet) {
	// TODO Auto-generated method stub
	FlowSet kills = (FlowSet)emptySet.clone();//Unit的kills
	Iterator defIt = u.getDefBoxes().iterator();
	while(defIt.hasNext()){
		ValueBox defBox = (ValueBox)defIt.next();

		if(defBox.getValue() instanceof Local){
			Iterator inIt = inSet.iterator();
			while(inIt.hasNext()){
				Local inValue = (Local)inIt.next();
				if(inValue.equivTo(defBox.getValue())){
					kills.add(defBox.getValue());
			}
		}
	<span style="white-space:pre">	</span>}
	}
	inSet.difference(kills, outSet);
}

private void gen(FlowSet outSet, Unit u) {
	// TODO Auto-generated method stub
	Iterator useIt = u.getUseBoxes().iterator();
	while(useIt.hasNext()){
		ValueBox e = (ValueBox)useIt.next();
		if(e.getValue() instanceof Local)
			outSet.add(e.getValue());
	}
}</span>

Flow sets

(此部分内容参考点击打开链接

在soot中,flow sets代表control-flowgraph中与节点相关的数据集合。Flow set存在有界限的(interface BoundedFlowSet)和无界限的(interfaceFlowSet)两种表达。有界限的集合知道可能值的全体集合,而无界限的集合则不知道。

Interface FlowSet<T>提供的关键方法有

<span style="font-size:14px;">FlowSet<T> clone() //克隆当前FlowSet的集合
FlowSet<T> emptySet() //返回一个空集,通常比((FlowSet)clone()).clear()效率更高
void copy(FlowSet<T> dest) //拷贝当前集合到dest集合中
void union(FlowSet<T> other) //FlowSet∪other = FlowSet
void union(FlowSet<T> other,FlowSet<T> dest) // FlowSet∪other = dest,其中other、dest可以与该FlowSet一样
void intersection(FlowSet<T> other) //FlowSet∩other = FlowSet
void intersection(FlowSet<T> other,FlowSet<T> dest) // FlowSet∩other = FlowSet,其中,dest、other可以和该FlowSet一样
void difference(FlowSet<T> other) // FlowSet-other = FlowSet
void difference(FlowSet<T> other,FlowSet<T> dest) // FlowSet-other = dest,其中,dest、other和FlowSet可能相同。
</span>

还有isEmpty()、size()、add(T obj)、remove(T obj)、contains(Tobj)、isSubSet(FlowSet<T> other)、iterator()、toList()等。

上述方法足以使flow sets成为一个有效的lattice元素。

当实现BoundedFlowSet时,它需要提供方法,该方法能够产生set‘s complement和its topped set(一个lattice element包括所有的可能的值的集合)。

Soot提供了四种flow sets的实现:ArraySparseSet,ArrayPackedSet,ToppedSet和DavaFlowSet。

ArraySparseSet:是一个无界限的flowset。该set代表一个数组引用。注意:当比较元素是否相等时,一般使用继承自Object对象的equals。但是在soot中的元素都是代表一些代码结构,不能覆写equals方法。而是实现了interface soot.EquivTo。因此,如果你需要一个包含类似binary operation expressions的集合,你需要使用equivTo方法实现自定义的比较方法去比较是否相等

针对intra-procedural analysis,本人实现了一个活跃变量的代码

import java.util.Iterator;

import soot.Local;
import soot.Unit;
import soot.ValueBox;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.scalar.ArraySparseSet;
import soot.toolkits.scalar.BackwardFlowAnalysis;
import soot.toolkits.scalar.FlowSet;

class MyAnalysis extends BackwardFlowAnalysis{

	private FlowSet emptySet;

	public MyAnalysis(DirectedGraph graph) { //构造函数
		super(graph);
		// TODO Auto-generated constructor stub
		emptySet = new ArraySparseSet();
		doAnalysis();//执行fixed-point
	}

	@Override
	protected void flowThrough(Object in, Object d, Object out) {
		// TODO Auto-generated method stub
		FlowSet inSet = (FlowSet)in,
				outSet = (FlowSet)out;
		Unit u = (Unit) d;
		kill(inSet,u,outSet);
		gen(outSet,u);
	}

	private void kill(FlowSet inSet, Unit u, FlowSet outSet) {
		// TODO Auto-generated method stub
		FlowSet kills = (FlowSet)emptySet.clone();//Unit的kills
		Iterator defIt = u.getDefBoxes().iterator();
		while(defIt.hasNext()){
			ValueBox defBox = (ValueBox)defIt.next();

			if(defBox.getValue() instanceof Local){
				Iterator inIt = inSet.iterator();
				while(inIt.hasNext()){
					Local inValue = (Local)inIt.next();
					if(inValue.equivTo(defBox.getValue())){
						kills.add(defBox.getValue());
					}
				}
			}
		}
		inSet.difference(kills, outSet);
	}

	private void gen(FlowSet outSet, Unit u) {
		// TODO Auto-generated method stub
		Iterator useIt = u.getUseBoxes().iterator();
		while(useIt.hasNext()){
			ValueBox e = (ValueBox)useIt.next();
				if(e.getValue() instanceof Local)
					outSet.add(e.getValue());
			}
		}

	@Override
	protected Object newInitialFlow() {
		// TODO Auto-generated method stub
		return emptySet.emptySet();
	}

	@Override
	protected Object entryInitialFlow() {
		// TODO Auto-generated method stub
		return emptySet.emptySet();
	}

	@Override
	protected void merge(Object in1, Object in2, Object out) {
		// TODO Auto-generated method stub
		FlowSet inSet1 = (FlowSet)in1,
				inSet2 = (FlowSet)in2,
				outSet = (FlowSet)out;
		//inSet1.union(inSet2, outSet);
		inSet1.intersection(inSet2, outSet);
	}

	@Override
	protected void copy(Object source, Object dest) {
		// TODO Auto-generated method stub
		FlowSet srcSet = (FlowSet)source,
				destSet = (FlowSet)dest;
		srcSet.copy(destSet);
	}

}
时间: 2024-10-20 08:47:38

基于soot的过程内数据流分析的相关文章

下载PHPDroid: 基于WebView和PHP内置HTTP服务器开发Android应用

基于Android上的PHP(比如我打包的PHPDroid),寥寥几行PHP代码,就能实现一个支持无线局域网用浏览器访问的Android手机的Shell,用于执行命令和PHP代码.       个人在Ubuntu上使用交叉编译工具链  arm-none-linux-gnueabi 或 musl-cross-compilers(推荐)  按照  DroidPHP 的教程 cross_compile_php.txt 这是我使用musl-cross-compilers交叉编译Android版PHP7的

期许伟大-基于CMMI的过程改进之道探索

原文作者:上海科维安信息技术顾问有限公司QAI China 何丹博士 CMMI主任评估师 一.引子     近年来,由美国SEI  (软件工程研究所)开发的SW-CMM  (软件过程能力成熟度模型) 模型以及改进后的CMMI (能力成熟度模型集成)模型得到了国际上的广泛认可.因此有越来越多的软件和IT公司已经或开始采用这些模型来开展相应的过程改进工作,来提高过程能力的 成熟度,以期使公司的软件或系统开发工作更加高效,更具有国际竞争力,这似乎已经成为一种潮流.很多公司都怀着这种美好的愿望开始了过程

Elasticsearch的分析过程,内置字符过滤器、分析器、分词器、分词过滤器(真是变态多啊!美滋滋)

分析过程 当数据被发送到elasticsearch后并加入倒排序索引之前,elasticsearch会对文档进行处理: 字符过滤:使用字符过滤器转变字符. 文本切分为分词:将文本(档)分为单个或多个分词. 分词过滤:使用分词过滤器转变每个分词. 分词索引:最终将分词存储在Lucene倒排索引中. 整体流程: 目的是达到人性化的分词 内置字符过滤器 HTML字符过滤器.映射字符过滤器.模式替换过滤器 HTML字符过滤器 POST _analyze { "tokenizer": "

基于soot的java方法名生成报告

0.生成XML格式文件 笔者使用soot将java文件解析生成xml格式文档,具体操作流程不再赘述.本文讨论执行结果的用途.笔者第一次采用的java文件如下:文件名为test.java 用soot解析后,生成如下所示的XML文件:    1.用xsl样式表链接XML文档 大家很容易看到上文是一个常见的xml文件,然后我使用Altova XMLSpy工具,编写XML文件对应的XSL文件,把 XSL 样式表链接到 XML 文档.即可生成如下所示的方法名列表,文件以HTML格式的方式预览:     2

基于shiro授权过程

1.对subject进行授权,调用方法isPermitted("permission串")2.SecurityManager执行授权,通过ModularRealmAuthorizer执行授权3.ModularRealmAuthorizer执行realm(自定义的CustomRealm)从数据库查询权限数据 调用realm的授权方法:doGetAuthorizationInfo 4.realm从数据库查询权限数据,返回ModularRealmAuthorizer5.ModularReal

关于ArcGis的二次开发-基于ArcEngine10.2(内有安装包)

网上很少有arcgis engine10.2的安装包,在这里我把安装包链接附上,是百度云,有需要的可以自己下--http://pan.baidu.com/s/1mhIhYYG 顺带着把arcgis desktop10.2安装包也附上吧,内涵中文语言包和破解文件--http://pan.baidu.com/s/1gflywGr arcgis desktop安装根据里边的安装教程自己做,arcgis engine10.2安装,首先安装.net arcobjects for C#,然后再安装.net

C++开发的基于TCP协议的内网聊天工具

项目相关地址 源码:https://github.com/easonjim/TCPChat bug提交:https://github.com/easonjim/TCPChat/issues

史上最详细Oracle 12c搭建过程(内附源码包)

简介 Oracle Database,又名Oracle RDBMS,或简称Oracle.是甲骨文公司的一款关系数据库管理系统.它是在数据库领域一直处于领先地位的产品.可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好.使用方便.功能强,适用于各类大.中.小.微机环境.它是一种高效率.可靠性好的适应高吞吐量的数据库解决方案. 优点 可用性强可扩展性强数据安全性强稳定性强 操作系统要求 物理内存不少于4Gswap交换分区不少于8G磁盘空间不少于30G挂载分区文件类型为x

ABAP 内表 详解

声明:原创作品,转载时请注明文章来自SAP师太技术博客:www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4293475.html 老式的内表类型定义... 214 基于基本类型内表类型... 214 基于结构体类型内表类型... 215 老式的内表对象创建... 215 参照现有内表类型或内表对象来创建... 215 参照现有结构类型或结构对象来