目录
本文以技术文章的方式回顾汤战勇老师在 SIG-编程语言测试 技术沙龙上的分享,回顾视频也已经上传 B 站:https://www.bilibili.com/video/BV1Ev411n7LK,欢迎小伙伴们点开观看。
大家好,我是来自西北大学的汤战勇,非常感谢华为编程语言实验室的邀请,很高兴有机会在这里给大家分享我们团队关于 JS 引擎测试方面的工作 —— COMFORT [1]。
COMFORT (COMpiler Fuzzing fOr javascRipT) 是我们团队提出的一个全新的编译器模糊测试框架,基于 ECMAScript Specification 来指导如何检测 JS 引擎的缺陷。COMFORT 利用了基于深度学习的语言模型的最新进展,自动生成 JS 测试代码。我们将 COMFORT 应用到 10 个主流的 JS 引擎上,在 200 小时的自动并发测试运行中,我们在被测的 10 个 JS 引擎中均发现了 bugs:共发现 158 个 JS 引擎 bugs,其中 129 个已通过验证,115 个已被修复。另外,COMFORT 生成的 21 个测试用例已经添加到官方 ECMAScript 的一致性测试套件 Test262 [2] 中。
我们已将 COMFORT 的代码和数据开源,欢迎大家试用。
# 引言 #
JS 语言是目前最流行的开发语言之一,截止 2021 年第一季度的统计,超过 4000W 的开发者,Github 上有超过 470W 的代码仓库。
除了常见的四种主流的浏览器引擎(比如 Apple Safari 中的 JavaScriptCore,Google Chrome 中的 V8,Microsoft Edge 中的 ChakraCore,Firefox 中的 SpiderMonkey),在很多的移动和嵌入式系统中还有广泛适用特定浏览器的 JS 引擎(比如 Hermes,QuickJS,Rhino,Nashorn,JerryScript,Graaljs),其中有些 JS 引擎是为了适应特定的轻量级应用。
为了保证 JS 脚本在各个浏览器中都能够执行,开发 JS 引擎需要遵循一定的开发规范(或者是标准)。可以理解的是,和大多数程序开发人员的开发的软件一样,JS 引擎不可避免的也会产生 bugs 或者是漏洞。如何检测 JS 引擎中的 bug 是研究人员一直关注的问题。
# 如何选择 JS 引擎的测试方法 #
Bug 检测的方法有很多,常见的有 程序分析、软件测试、形式化证明 等,这些方法均能发现软件的缺陷。其中 软件测试 是目前被广泛使用的程序缺陷的检测方法,包括 黑盒测试、灰盒测试 和 白盒测试 等方法。
模糊测试 fuzzing 是自动缺陷检测的重要的方法和途径之一 [4, 5, 6]。TSE2019 上有研究人员对目前的模糊测试的工具做了个整体的展示,我们看到,目前这个领域一直都比较热门,研究人员不断的尝试和改进已有的模糊测试方法,以求触发更多的软件缺陷。
对于给定的编译器(JS 引擎),如果执行某一个测试用例,可能输出的结果有几种,包括正常输出、异常、Crash,以及也有可能出现执行超时情况。如果 JS 引擎运行结果 crash 或者超时,我们很容易判断引擎可能存在 bugs。但是,如果我们发现引擎输出结果、或者抛出异常,又该如何判断所输出的结果或抛出的异常是否正确呢?
目前看来,为了检测引擎的 bugs,在模糊测试框架中,使用 差分测试 是较为有效的手段之一 [7, 8, 9]。利用 多数投票表决 的方法快速的判断哪些引擎的输出存在问题(与其它不一致的行为),然后加以验证。
# 设计 JS 引擎的模糊测试用例生成技术 #
如何产生有效的高质量的测试用例一直是目前模糊测试面临的挑战。 对于 JS 引擎的差分模糊测试而言,其用例由 程序 和相应的 输入 两方面构成,且测试用例的输入对于被测对象的代码覆盖尤其重要。所以,从一定程度上讲,生成正确的输入较为困难。但同时,我们也发现输入类型正确的数据对发现引擎的 bugs 非常重要。
如何能够输入类型正确的数据呢?我们首先想到了 JS 引擎的开发规范,我们希望通过利用标准来知道测试用例中数据的生成,从而产生高质量的测试用例。
以一个简单的 case 为例,这是一个由 GPT-2 预训练模型生成的例子:
function foo(str, start, len) {
var ret = str.substr(start, len);
return ret;
}
var s = "Name:␣Albert";
var pre = "Name:␣";
var len = undefined;