今年 2 月,微软研究院与剑桥大学宣布合作开发了一种名为
DeepCoder 的新算法
,可以根据问题的输入输出自动编写解题程序。但事实上,DeepCoder 的实现是基于一种原创的、极其精简的语言,还不能独立处理较为复杂的问题,目前业界使用的编程语言对于它来说还难以掌握。所以广大程序员们完全不用担心会被机器取代!
那么除此以外程序员们最担心的是什么呢?大概就是调 Bug 了吧~ 鉴于机器已经可以完成简单的编程任务,我们当然希望能利用它更好地辅助程序员的工作。
为此,北京大学、微软亚洲研究院和电子科技大学的研究人员联合开发了一种新技术 ACS (Accurate Condition Synthesis)。该技术可以全自动修复软件系统中的缺陷,无需用户干预。
比如,下面这段代码来源于 Apache Math 库,用于求两个数的最小公倍数。该段代码采用了绝对值函数 Math.abs 来保证返回的值是一个正数。但由于实现上的缺陷,在某些输入的时候会返回负数。
int lcm=Math.abs(mulAndCheck(a/gdc(a,b), b));
return lcm;
这个缺陷的根源是因为负数的数值范围比正数多一个,所以当传给 Math.abs 的值是 Integer.MIN_VALUE 时,Math.abs 并不能将输入转换成正数,进而导致函数产生负数的输出。一个正确的实现应该在这个时候返回 ArithmeticException()。
现在假设有一个测试来捕获这个错误,该测试的输入为 a=Integer.MIN_VALUE 和 b=1,期望的输出为 ArithmeticException。很显然,这个测试将在该程序上运行失败,因为并没有异常被抛出。
但当我们将这个程序和相应的测试提供给 ACS 时,ACS 将会自动生成如下补丁,准确的修复了该缺陷:
int lcm=Math.abs(mulAndCheck(a/gdc(a,b), b));
+ if (lcm == Integer.MIN_VALUE) {
+ throw new ArithmeticException();
+ }
return lcm;
事实上,缺陷修复技术由来已久。自 2009 年的 GenProg 技术以来,学术界已经提出了数十种不同类别的缺陷修复方法。但传统的缺陷修复技术一直面临一个问题——缺陷修复正确率非常低。这是因为传统缺陷修复系统以通过测试为目标,但实际软件系统中,测试往往数量有限,通过测试并不意味着程序就是正确的。
比如上面这个例子,现有系统可能生成如下补丁:
int lcm=Math.abs(mulAndCheck(a/gdc(a,b), b));
+ if (b == 1) {
+ throw new ArithmeticException();
+ }
return lcm;
甚至如下补丁:
int lcm=Math.abs(mulAndCheck(a/gdc(a,b), b));
- return lcm;
+ throw new ArithmeticException();
这些补丁都能通过测试,但却与正确程序差别甚远。其实,在这个例子中,我们可以很容易地找到能够通过测试的上百个不正确的修复,这将导致修复技术的正确率变得非常低。
根据 2015 年初美国麻省理工学院的 Martin Rinard 教授在其 ISSTA 论文中的发现,主流缺陷修复技术在真实缺陷上的正确率不超过 10%。虽然后来出现了一些改进的技术,如麻省理工学院的 Prophet 和新加坡国立大学的 Angelix,但这些技术的正确率也都没有超过 40%。这就意味着,这些技术所产生的补丁中,大多数是错误的。而这样的技术基本没有办法在实践中使用。
而 ACS 技术的正确率和之前的技术相比有了显著提升。在缺陷修复的基准数据集 Defects4J 上的测试结果中,ACS 生成了 23 个补丁,其中 18 个是正确的,修复正确率接近 80%,显著超越了现有技术。而在正确率大幅提升的同时,ACS 在该数据集上正确修复的缺陷数量也是同类方法中最多的。目前 ACS 的修复正确率和修复数量都取得了该数据集上的最好结果。