孙军 新加坡管理大学教授,研究方向为:形式化方法、软件工程、安全等,爱好:爬山、攀岩等。
如果读者想了解更多有关程序分析相关的技术内容,欢迎加入编程语言技术社区 SIG-程序分析。
加入方式:文末有小助手微信,添加并备注加入 SIG-程序分析。
目录
# 引言 #
程序分析是以某种语言书写的程序为对象,对其内部的运作流程进行分析,自动分析计算程序的正确性以及高效性等属性的过程。
虽然经过了几十年的发展,程序分析仍是一个持续热门的研究领域。由于现代软件的复杂性,大型程序的正确性、性能和安全性等都面临新的挑战,所以程序分析技术不只在学术界被大批学者研究,近些年来也越来越受到企业界的青睐。随着大型软件企业逐渐意识到程序分析的重要性,投入做程序分析的公司也越来越多,如 Microsoft、Google、Apple、Facebook 和华为等都有研发团队从事程序分析工作,以及我们熟知的 Coverity、Semmle 等,此外,国内也涌现出很多做程序分析相关的企业如思码逸 Merico、鸿渐 RedRocket、鉴释 Xcalibyte、源伞 SourceBrella 等。
程序分析主要关注两大方面:
- 程序优化侧重于提高程序的性能,通过对程序中关键函数的跟踪或者运行时信息的统计,找到系统性能的瓶颈,从而采取进一步行动对程序进行优化,同时减少资源使用。
- 程序正确性侧重于确保程序执行它应该做的事情,帮助开发者找出错误代码的位置。(本文以程序正确性的分析为主)
自图灵祖师爷开天辟地以来,怎么保证程序的正确性就一直是一个老大难问题。无数大牛们尝试了各种方法来解决这个问题,结局是各种幻灭。但与此同时,这也造就了现在各种程序分析技术以及产品百花齐放的局面。本文就几种常见程序分析技术及其由来进行了简单的介绍,希望能帮助大家对程序分析有一个初步的了解。
# 程序分析很难! #
计算机发展早期,程序很简单,程序的正确性需求(specification)也很简单,因此,程序的正确性常常显而易见,或者很容易被手动证明。
自然而然地,大家就产生了一种幻觉,可能我们只需要说明我们想要满足什么样的需求,就可以根据需求自动地生成一个程序。如果这样可行的话,程序员的工作无疑将变得轻松无比。换句话讲,我们希望找到一个万能的程序。即,给定任意的需求,这个程序都能自动的生成一个特定的程序来满足需求。
这个问题在不同的设定下被反复地定义与研究,吸引了无数大神级的计算机科学家曾尝试解决这个问题,包括 Turing、Church、Buchi、Landweber、Pnueli、Clarke 等等。结论是,除了某些意义非常有限的设定,这个问题是不可判定的 [1]。换句话说,不存在这样一个万能程序。当然,更积极一点的说法是,程序员无可替代,程序员需要不停地工作来为特定的用户需求开发特定的程序,软件行业继而蓬勃发展。
然而,毫无保留地信任程序员是要付出代价的。很快,历史证明了程序员编写的程序常常有意或者无意地包含了各种错误、安全漏洞或者后门。
计算机科学家们退而求其次,开始研究如何验证程序员编写的程序的正确性。我们的问题变成了:给定一个特定的程序和一个特定的需求(例如,没有某种特定的漏洞),我们能不能有工具可以自动的判断这个程序是不是满足需求。 这个问题同样被证明是不可判定的。我们只能依赖各种不完备的方法来尽可能找到程序的错误,或者在有限的情况下证明程序的正确性。
程序分析的方法自此百花齐放。
# 知道什么是程序正确性很难!
我们不仅放弃了保证程序正确的梦想,同时也在“正确性”的定义上节节败退。
在上个世纪,理想主义的计算机科学家们天真地认为,正确的编程方式应该是程序员先逻辑精确地表达程序的正确性需求(即 specification),然后再根据该正确性需求来实现程序,最后说明为什么该程序正确。
比如 Dijkstra 在 1969 年很自信地说过 [2],
“After this decade, programming could be regarded as a public, mathematics-based activity of restructuring specifications into programs.” (十年之后,编程将变成一种基于数学的,把正确性需求翻译成程序的过程。)
然而并非如此。
假设“程序员会花时间把需求详细正式地写出来”已经被一而再,再而三地证明太傻太天真。刚开始的时候(也就是计算机科学家们还没有遭受现实的拷打的时候),很多 specification 语言被发明出来。比如 Oxford 的 Z 语言 [3],Hoare 的 Communicating Sequential Processes (CSP) [4] 等等。计算机科学家们想象的是,只要我们设计的 specification 语言够直观够好用,程序员们自然就会用。毕竟,有了 specification,我们才能讨论程序正确性的问题啊。
然而并没有发生。
再后来,计算机科学家们扪心自问,为什么这么多这么好的 specification 语言都没有人用,难道是因为程序员们不愿意学一门新的语言?如果是这样,我们提供方法让程序员可以在他们常用的语言里写 specification 就好了嘛。
基于这样美好的想法,Meyer 提出了 Design-by-Contract(把程序的 specification 在程序里写成 code contract [5] [6] [7]),同时 Java Modeling Language (JML) [8] 和(基于 C# 的)SPEC# [9] 两个项目把 Meyer 的想法在主流的程序语言里几乎完美的实现了出来。
然而并没有用。
除了少数几个项目,程序员们并不愿意花额外的时间来写 specification,即使是基于是基于 Java 或者 C#。
计算机科学家们最后的挣扎包括断言(assertion, 即“尽量在相关的地方