KLEE应用实例2



原文地址:http://klee.github.io/tutorials/testing-regex/

    测试一个简单的正则表达式的匹配函数。该实例的源程序在klee_dir/examples/regexp/regexp.c。通过本例将会学习如何通过KLEE编译和运行具体的实例,以及如何解读输出。

1 编译构造(build and run the example)

   原文的命令行为: $ llvm-gcc -I ../../include -emit-llvm -c -g Regexp.c  (因为假设用户所在文件夹为klee_dir/examples/regexp)

  -I的目的是为了指定要包括的klee.h文件。我是把klee_dir/include加入到环境变量中,所以不需要设置该参数,只需要如下命令行:$ llvm-gcc -c -g Regexp.c  (把include目录加入到环境变量更好,以后可以省略-I参数的指定)。

    -c参数设定输出为Regexp.o文件,-g参数设定输出中包括编译信息,以便klee可以定位源代码。

    若你正确安装好LLVM,那么可以利用工具llvm-nm验证上述步骤,运行和输出如下:

    $ llvm-nm Regexp.o
          t matchstar
          t matchhere
          T match
          T main
          U klee_make_symbolic_name
          d LC
          d LC1

    通常情况下,要运行程序需要先创建可执行文件。不过由于该程序只有一个文件,无需进行link操作,所以KLEE是直接在LLVM的位代码基础上运行。对于"real programs“存在多个文件的情况,可以使用LLVM的llmv-link和llvm-ld进行链接,把多个文件合并为一个module,然后可以被KLEE执行。


2 执行 explain the output

    执行命令以及输出如下,信息很直接了(其中参数 --only-output-states-covering-new是用于限定输出,若不指定,会生成大量的ktest测试数据,指定该参数则仅仅输出新覆盖输出):

  $ klee --only-output-states-covering-new Regexp.o
  KLEE: output directory = "klee-out-1"        输出文件夹,也可以自己指定,在运行时设置-output-dir=path

  KLEE: ERROR: .../klee/examples/regexp/Regexp.c:23: memory error: out of bound pointer
  KLEE: NOTE: now ignoring this error at this location
  KLEE: ERROR: .../klee/examples/regexp/Regexp.c:25: memory error: out of bound pointer
  KLEE: NOTE: now ignoring this error at this location
  KLEE: done: total instructions = 6334861
  KLEE: done: completed paths = 7692
  KLEE: done: generated tests = 22

  缺省情况下,KLEE会遍历所有的路径,对于有些程序就需要花费很多时间,或者无限时间,所以KLEE可以通过ctrl+c终止运行,也可以通过设置如下的参数,对运行和路径进行限制。

    -max-time=seconds: 指定最大运行时间.

    -max-forks=N:  在N符号分支后停止,并且运行剩余路径在终止(Stop forking after N symbolic branches, and run the remaining paths to termination)

    -max-memory=N: 用于指定最大可以消耗的内存,单位为MBytes


3 错误报告(Error reports)

    当KLEE在执行程序时发现错误,那么它会生成一个test case来展示该错误,并把相关信息写入文件testN,类型TYPE为err的文件中。KLEE可以发现的错误包括:

ptr: Stores or loads of invalid memory locations.读写不可用的内存
free: Double or invalid free(). 多次free同一空间或者是不可释放的空间
abort: The program called abort(). 程序调用abort
assert: An assertion failed. asset断言错误
div: A division or modulus by zero was detected. 除数为0的情况
user: There is a problem with the input (invalid klee intrinsic calls) or the way KLEE is being used. 不可用的klee调用
exec: There was a problem which prevented KLEE from executing the program; for example an unknown instruction, a call to an invalid function pointer, or inline assembly. 由于某些原因阻止KLEE执行程序,例如未知的指令,调用无效函数指针,或者内联汇编
model: KLEE was unable to keep full precision and is only exploring parts of the program state. For example, symbolic sizes to malloc are not currently supported, in such cases KLEE will concretize the argument. KLEE不能够保证准确性的情况

     KLEE会在控制台打印出错误信息,对所有的程序错误,KLEE会把backtrace写入.err文件。下面是一个错误实例:

Error: memory error: out of bound pointer
File: .../klee/examples/regexp/Regexp.c
Line: 23
Stack:
  #0 00000146 in matchhere (re=14816471, text=14815301) at .../klee/examples/regexp/Regexp.c:23
  #1 00000074 in matchstar (c, re=14816471, text=14815301) at .../klee/examples/regexp/Regexp.c:16
  #2 00000172 in matchhere (re=14816469, text=14815301) at .../klee/examples/regexp/Regexp.c:26
  #3 00000074 in matchstar (c, re=14816469, text=14815301) at .../klee/examples/regexp/Regexp.c:16
  #4 00000172 in matchhere (re=14816467, text=14815301) at .../klee/examples/regexp/Regexp.c:26
  #5 00000074 in matchstar (c, re=14816467, text=14815301) at .../klee/examples/regexp/Regexp.c:16
  #6 00000172 in matchhere (re=14816465, text=14815301) at .../klee/examples/regexp/Regexp.c:26
  #7 00000231 in matchhere (re=14816464, text=14815300) at .../klee/examples/regexp/Regexp.c:30
  #8 00000280 in match (re=14816464, text=14815296) at .../klee/examples/regexp/Regexp.c:38
  #9 00000327 in main () at .../klee/examples/regexp/Regexp.c:59
Info:
  address: 14816471
  next: object at 14816624 of size 4
  prev: object at 14816464 of size 7 

每一行的backtrace包含 frame number, the instruction line (汇编程序assebly.ll的行号),函数,参数和源代码位置信息。对于不同的错误,其所含信息也不同,例如内存错误,KLEE会显示无效地址、以及堆中的对象是什么,以及前后的地址。本例中,可以看到错误地址发生在上一个对象地址的下一个字节位置。


4 Changing the test harness (改变测试的方法)

    本例中KLEE发现内存错误并不是因为正则表达式函数存在bug,而是因为test driver的问题,因为我们制定输入regular expression缓存为completely symbolic,但是match函数期望该regular expression是一个空字符终止的串。这个问题可以按照如下步骤加以解决。

     最简单的方法就是在符号化后,在buffer后面增加串结束符号‘\0’。 程序如下:

int main() {
  // The input regular expression.
  char re[SIZE];
 
  // Make the input symbolic.
  klee_make_symbolic(re, sizeof re, "re");
  re[SIZE - 1] = '\0';

  // Try to match against a constant string "hello".
  match(re, "hello");

  return 0;
}

    另外一种方法是使用klee_assume函数,设置为re[SIZE - 1] == '\0',确保符号化生成的re是以‘\0'结束。程序修改如下:

int main() {
  // The input regular expression.
  char re[SIZE];
 
  // Make the input symbolic.
  klee_make_symbolic(re, sizeof re, "re");
  klee_assume(re[SIZE - 1] == '\0');

  // Try to match against a constant string "hello".
  match(re, "hello");

  return 0;
}

在该例中,两种方法都可以,但是klee_assume相对更加灵活。

在klee_assume的应用中,注意&&和||的short-circuiting特性(这个在前面已经详细讲过)。所以建议先运算,然后klee_assume中使用单个变量值,或者使用'&' 和 '|' 操作来替代。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值