【软件分析/静态程序分析学习笔记】7.指针分析(Pointer Analysis)入门

写在前面的话

本渣有幸成为南京大学软件学院研究生,在前往仙林校区蹭课的时候偶然发现了这门宝藏课程,听了以后感觉深有收获,但又因为课程难度较大,国庆假期归来发现遗忘较多,因此开了一坑来记录自己对每节课知识点的理解。也由于这是本人第一次开坑写博客,结构内容自有诸多不合理之处,希望有问题的地方大家可以指出。


系列文章目录

1.静态程序分析(Static Program Analysis)介绍
2.中间表示(Intermediate Representation)
3.数据流分析(Data Flow Analysis) (上):可达性分析(Reaching Definitions)
4.数据流分析Data Flow Analysis) (下):存活变量分析(Live Variables Analysis)及可用表达式分析(Available Expressions Analysis)
5.数据流分析基础(Data Flow Analysis-Foundations)
6.过程间分析(Interprocedural Analysis)
7.指针分析(Pointer Analysis)入门
8.指针分析基础知识(Pointer Analysis Foundations)


一、动机

动机
在上一篇文章中,我们讲到了一种过程间分析的算法CHA,这是一种牺牲了精度来换取效率的算法,可以根据对象的类型进行分析,得到这个对象调用的方法可能是在哪定义的。然而这种算法对精度的牺牲自然会导致一些我们不想看到的"严谨",就像上图所示,采用CHA算法会从对象n对应的类Number中寻找get()的定义,找不到后会从Number的子类寻找,因此经过CHA的分析n.get()的返回值是NAC。然而显而易见,由于n是One类型创建的,所以返回值应该是1才对,这就需要用到指针分析了。


二、指针分析

2.1 什么是指针分析

我们首先介绍一下指针分析的三个特征:

  • 一个基本的静态分析:计算一个指针能指向哪个内存位置。
  • 对于OO语言(主要是Java)来说:计算一个一个指针(variable或field)指向哪个对象。
  • 作为一个may分析:计算指针指向的过拟合的对象集,即一个指针可能指向哪些对象?、

以上三个特征便可以看出指针分析到底是一种什么样的分析算法,其中需要解释一下的是第二条特征。不同于cpp,Java并没有真正的指针,或者说Java的指针被封装在代码底层,我们接触不到,而此处的指针指的是那些存储非数据而是地址的变量,例如T x = new T()中的x存储了新创建的一个类型为T的对象的地址,是一个指针。

2.2 一个指针会指向哪里

接下来用一个例子来具体感受一个指针会指向哪里:
例子
右侧表格是左侧程序每个变量指针指向的对象,接下来一个个看。
第一、二行定义了a和x,分别指向A和B没问题;
第三行调用了A类中的set()函数,this指向当前对象,同时也是调用了这个方法的a指向的new A,而b指向自己新创建的new B;
而y指向了a.getB()返回的this.b所指向的new B;
下方的A.b即this.b,指向传入参数x的new B。

2.3 Pointer Analysis 和 Alias Analysis

Pointer Analysis是指针分析;
Alias Analysis是别名分析;
这是两个密切相关但是不同方面的分析,主要体现在:
指针分析主要分析指针指向哪个对象,而别名分析主要分析两个指针是否指向同一个对象。
这个点了解一下区别就可,不细说了。

2.4 指针分析的应用

指针分析有很多的应用场景,例如可用于

  • 优化代码
  • 查bug
  • 安全性分析
  • 验证测试

等技术场景。


三、指针分析中的关键因素

指针分析是一个复杂的系统,有不同的因素影响了这个系统的效率和精度,我们需要在此之间找到一个平衡,下图就是其中最重要的四个因素
在这里插入图片描述
四个因素分别是:堆抽象、上下文敏感、流敏感、分析范围,第三列则是一些最为广泛使用的选择策略。

3.1 堆抽象

Java运行时会将创建的很多的对象放在堆里以供调用,堆抽象就是对其建模。
为了确保终止性,堆抽象会将动态执行时无限的域映射到静态分析时有限的域,再进行静态分析:在这里插入图片描述
在这里插入图片描述
堆抽象有很多种方法,最常用到的就是Allocation sites的抽象技术,这是一种Store based model,基于内存中地址的模型。
我将Allocation site翻译为抽象点,每个抽象点对应一个抽象对象,这个抽象对象代表被分配的所有具体对象,而系统通过抽象点对具体对象建模。
下面举个例子说明这种抽象关系:
在这里插入图片描述
动态运行时在for语句中创建了多个具体的对象a,而通过Allocation sites的技术抽象为一个抽象对象。

3.2 上下文敏感

上下文的敏感指的是系统模拟如何调用上下文,例如记录一个方法的传参、返回地址等,其中的上下文指的是被调方法的上下文。在这里插入图片描述
左侧是上下文敏感的做法,对于每次调用方法的时候都会分别记录那次方法的上下文信息,而右侧是不敏感的做法,会将不同的调用合并,每个方法不论调用多少次都只会分析一次。

3.3 流敏感

流敏感指的是如何对控制流进行建模,我们之前学习到的算法都是流敏感的:在这里插入图片描述
左侧是流敏感的分析,严格按照控制流的顺序进行分析,会在每个程序点都列出当前所有的指针指向;
右侧是流不敏感的分析,不考虑控制流的顺序,会将所有可能的指向一起加入域中。
由于流敏感分析的时候很多情况下域中的指向对象不可替换,因此开销很大,流不敏感的分析此时便可派上用处。

3.4 分析范围

分析分为整体分析和按需求分析。其中整体分析就是分析整个程序,不需要解释;按需求分析就是分析需要的代码行及相关的代码

1 x = new A();
2 y = x;
34 z = new T();
5 z.bar();

例如我要分析第五行的指针指向何处,只需要分析第四行即可。

3.5 总结

在这里插入图片描述
总结一下:

  • 堆抽象:针对对象,选择Allocation-site抽象技术;
  • 上下文敏感:针对方法,后续两种都会用到;
  • 流敏感:针对控制流,为了减小开销,使用流不敏感的;
  • 分析范围:由于并不知道得到需要分析处的指针指向需要从哪开始分析,有可能从头分析,消耗资源也很大,因此选择整体分析。

四、相关的语句

由于

  • if-else
  • switch-case
  • for/while/do-while
  • break/continue

四种语句并不会改变指针的指向,所以不考虑这四种语句的影响,主要分析以下四种类型的对象

  • Local variable: x
  • Static field: C.f
  • Instance field: x.f
  • Array element: array[i]

第一个局部变量x不用赘述;
第二个静态域C.f某些时候也可看作全局变量,一般不会碰到;
第三个实例域x.f建模为 一个由x指向的对象 + 一个域f;
第四个数组元素在处理的时候会将其下标忽略,统一指向一个域,将array[i]全部抽象映射到array.arr的域中。

然后是五种会改变指针指向的操作:在这里插入图片描述
这四种操作的需要牢记,将会在下一篇文章中具体分析。


五、总结

本文大概写了一下指针分析是什么,有哪些关注点,可以粗浅地了解一下什么是指针分析,具体的分析将在下一篇文章中进行。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值