论文名:SMOKE: Scalable Path-Sensitive Memory Leak Detection for Millions of Lines of Code
来源会议:ICSE 2019
来源团队:香港科技大学(源伞团队)
简介
尽管过去几十年工业界和学术界都花很大努力在检测内存泄露漏洞上,但是在工业界级的代码量上的效果一直不是很好。现有的工作存在一个很难解决的悖论问题——牺牲扩展性换取高精度,或者扩展性好,但精度不高。
这篇文章用了staged approach(分步骤)来解决这个问题。第一步,使用扩展性好但是不精确的分析去计算候选的内存泄露路径。第二步,使用更精确的分析去验证这些候选路径的可行性。第一步是可扩展的,因为使用了新的稀疏程序表示方法——use flow graph(UFG)。UFG能够进行多项式时间状态分析。第二步是精确和高效的,因为只有很小部分的候选路径,并且设计了小巧的约束求解器。
实验结果表示SMOKE能够检测高达800万行的代码,并且误报只有24.4%。同时,SMOKE比现有的工业工具都要快,大概快5.2x到22.8x之间。在29个成熟的常用的benchmark里,smoke发现了30个未知的漏洞,均被开发者验证,其中1个有CVE-ID。
要解决的问题
内存泄露漏洞很多。
- 2018上半年仅仅火狐浏览器和谷歌浏览器就检测出超过680个内存泄露漏洞。
- 2017年超过240个CVE都是内存泄露漏洞。
现在的检测工具在扩展性和准确性做权衡。
其中一类工作牺牲路径敏感性来换取扩展性,但同时精确度也不高。比如SABER,最近的一个路径不敏感的内存泄露检测技术,在我们的评估中有66.7%的误报。
另外一种工作,遍历控制流图,并使用路径敏感分析来实现高精度。然而经常会遇到扩展性问题,尤其是对整个程序进行分析时。比如SATURN在500万行的代码上检测内存泄露需要超过23小时。其他的比如CSA和INFER,两个小时后就扑街了。
如何解决的
作者发现程序中只有一小部分的路径会导致内存泄露。为了检测成千上百万行的代码,作者认为稀疏值流分析可以通过VFG来追踪数据依赖图的关系,并且效果要比控制流图要好。然而,作者发现VFG要检车任意的有限状态机属性(比如内存泄露问题)效果不是很好。作者再简单证明了一下直接用VFG方法来检测内存泄露问题是个NP难问题。
为了解决这一问题,作者扩展了VFG,叫做UFG,将堆对象的定义和使用都编码进图了。所有堆对象的使用的地方根据控制流图来排序,并且用多项式时间图搜索方法来找到潜在的内存泄露路径。验证过程是很高效的,平均路径长度只有21…作者使用了约束求解器来过滤掉一些矛盾的路径。最后用z3来解决剩下的候选路径。
smoke系统的框架如下图所示。作者将LLVM 字节码文件作为输入。首先预处理阶段使用流敏感和上下文敏感的指针分析去计算数据依赖。同时在控制流图的逆向图里计算控制依赖。为了构建调用图,我们使用must-alias结果来解决函数指针的问题,同时用class hierarchy 分析来解决虚函数调用问题。在状态分析里,只考虑内存分配操作成功的情况。比如,x=malloc()。
下面几张图感觉很浅显易懂,让我们知道文章的UFG图到底干了啥。
到达的效果如何
作者选择的测试程序有SPEC2000和17个开源程序。同时和相关工作SABE,PINPOINT,CSA和INFER做了对比。主要针对扩展性、准确性和召回率做了评估。并且还对两个步骤的贡献程度做了评估。此外还贴了代码说明自己的误报在哪里。
扩展性的实验结果如下:
准确性和召回率的结果:
两个分析步骤的数据:
一个误报例子:
还有哪些没解决的
在某些情况下准确率也不好。
-
lack of library specification,详见figure11
-
指针分析自身的不精确的问题。
-
有些在分支条件里弄了很多复杂运算、或者复杂数据依赖、或者很深的过程间影响的路径都没办法识别出来。牺牲扩展性可以缓解该问题。
总结
感觉文章的图画的不错,写作上也很清晰,以后写论文可以照这篇来写。
总体来说是不错的工作。值得借鉴学习!
文章工作开源于:https://smokeml.github.io/