使用Csmith测试C编译器

  |   0 评论   |   291 浏览

原文链接: 使用Csmith测试C编译器

前言

系统软件如编译器无论在小型还是大型软件系统中都有着相当重要的作用,一个编译器的bug很有可能对软件带来灾难性的影响。因此,测试编译器变得尤为重要。本文将介绍如何使用Csmith测试常见C编译器如GCC,LLVM。关于其具体实现原理我将另外写一篇文章详细介绍。

什么是Csmith

Csmith是一个可以随机产生有效C程序的软件,它可通过随机测试(也称为模糊 测试)帮助发现编译器中的错误。在给定实现C标准的多个C编译器情况,我们通常可以通过运行多种不同版本编译器并比较它们的输出来判定是否产生了编译器的bug。目前Csmith已经发现了超过400个编译器bug,包括在GCC和LLVM 上的。Csmith主页见 Csmith.

常见的测试为差分测试,如下图

null

大概的测试流程分为以下几步:

  • 第一步,使用Csmith生成大量有效C程序
  • 第二步,将同一C程序运行在不同版本的编译器上(或者运行在同一编译器的不同编译选项上)
  • 第三步,比较编译器的输出,如果编译出的结果不同,则说明肯定有错误,取大部分产生的结果为正确输出,少数的为错误输出。

安装及使用

使用环境:Ubuntu 18.04

1 下载源码 (目前最新为2.40版)

git clone https://github.com/csmith-project/csmith.git

2 编译

cd csmith
cmake .
make

3 简单生成测试代码

csmith > test.c

此时在当前目录下即可看见自动生成的 test.c 文件还有一个平台信息文件。

4 使用脚本重复测试 (脚本文件为test-csmith.sh)

set -e
for ((i=0; i<10000, i=i+1))
do
  csmith > test.c;
  gcc-4.0 -I ${CSMITH_HOME}/runtime -O -w test.c -o /dev/null;
done

执行脚本文件

./test-csmith.sh

此时,Csmith将会不断产生新程序不断测试,可以将gcc-4.0换成其他版本或者加上其他不同的编译优化参数进行测试,最后判断输出是否一致。

相关工作

在编译器测试领域还有其他一些代码生成技术,如何生成有效的程序并且快速找到bug还是比较火并且是有挑战性的。

以下摘自一篇最新的编译器测试综述 《A Survey of Compiler Testing》,感兴趣的朋友可以看原文。

文章中统计了目前编译器测试研究领域的基本情况,主要有一下几个研究热点:

  • 如何构造有效的程序输入,程序往往是高度结构化的;
  • 如何解决测试的Oracle问题,即如何判断一个程序的输出是正确的;
  • 如何优化测试的进程,包括时间和空间上的优化;
  • 如何处理大量的crash,人工处理crash非常耗时且难度大;
  • 如何从已有的编译器测试中学习经验,指导编译器测试的发展。

compilertu1.png

下图是编译器在以上五个方向中研究论文的数量及总体研究情况。

compilertu2.png

可以看出,近几年学术界对编译器的测试工作还是越来越感兴趣的。

思考

  • 系统软件的缺失是我国的“卡脖子”难题,我国目前也在不断加大对系统软件的投入。包括华为的方舟及鸿蒙的研究。

  • Csmith这个工具的缺点可能是这些自动生成的程序和人写的代码还是有一定的差距,比如一些特定的函数,如求阶乘,不能有效生成,这类函数的测试如何解决?

参考:

1 Csmith 原文 (2011 PLDI Finding and Understanding Bugs in C Compilers).
2 2019最新编译器测试综述 《A Survey of Compiler Testing》.

评论

发表评论