首先,能够分析klee源码固然重要。但是目前尚未到那个地步。我按照我的过程,记录和分析我所做的实验。

结论性内容是:

1、klee处理printf传入符号值的情形时,报为error,不会将符号值具体化以后再调用printf进行具体执行。

2、klee处理error的时候,如果多条路径覆盖该error,则只报一次该error,并且只生成一个测试用例。

3、klee符号执行时的posix-runtime选项为命令行建模提供支持,uclibc则对atoi等c标准库的函数进行建模。

(如果使用了Posix-rutime选项,但是没有对命令行建模(--sym-args和--sym-arg选项),则会报错;如果没有使用uclibc选项,那么klee符号执行过程会提示atoi等函数是external,无法处理。)

 

示例代码1:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <klee/klee.h>
int main(int argc, char* argv[]) {
int result = argc > ? atoi(argv[]) : ;
printf("result:%d\n",result);
if (result == )
{
printf("yes\n");
klee_assert();
}
// printf("result:%d\n",result);
}

示例代码2:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <klee/klee.h>
int main(int argc, char* argv[]) {
int result = argc > ? atoi(argv[]) : ;
//printf("result:%d\n",result);
if (result == )
{
printf("yes\n");
klee_assert();
}
printf("result:%d\n",result);
}

运行脚本:

clang -I /home/klee/xiaojiework/klee/include/ -emit-llvm -c -g test2.c
klee --optimize --libc=uclibc --posix-runtime test2.bc --sym-args

运行结果:

修改前

klee@ubuntu:~/kleeexperiment/modeltest$ clang -I /home/klee/xiaojiework/klee/include/ -emit-llvm -c -g test2.c
klee@ubuntu:~/kleeexperiment/modeltest$ klee --optimize --libc=uclibc --posix-runtime test2.bc --sym-args 0 1 3
KLEE: NOTE: Using klee-uclibc : /usr/local/lib/x86_64-linux-gnu/klee/runtime/klee-uclibc.bca
KLEE: NOTE: Using model: /usr/local/lib/x86_64-linux-gnu/klee/runtime/libkleeRuntimePOSIX.bca
KLEE: output directory is "/home/klee/kleeexperiment/modeltest/klee-out-12"
KLEE: Using STP solver backend
KLEE: WARNING: undefined reference to function: puts
KLEE: WARNING ONCE: calling external: syscall(16, 0, 21505, 62967648)
KLEE: WARNING ONCE: Alignment of memory from call "malloc" is not modelled. Using alignment of 8.
KLEE: WARNING ONCE: calling external: printf(51779744, 0)
result:0
result:0
result:0
result:0
result:0
result:0
result:0
result:0
KLEE: ERROR: /home/klee/kleeexperiment/modeltest/test2.c:19: external call with symbolic argument: printf
KLEE: NOTE: now ignoring this error at this location
result:0
result:0
result:0
result:0
result:0
result:0
result:0
result:-9
result:-9
result:0
result:0
result:-9
result:0
result:9
result:-99
result:9
result:9
result:9
result:9
result:9
result:9
result:9
result:99
result:99
result:99
result:99
result:999 KLEE: done: total instructions = 6238
KLEE: done: completed paths = 68
KLEE: done: generated tests = 36

修改后:

klee@ubuntu:~/kleeexperiment/modeltest$ clang -I /home/klee/xiaojiework/klee/include/ -emit-llvm -c -g test2.c
klee@ubuntu:~/kleeexperiment/modeltest$ klee --optimize --libc=uclibc --posix-runtime test2.bc --sym-args 0 1 3
KLEE: NOTE: Using klee-uclibc : /usr/local/lib/x86_64-linux-gnu/klee/runtime/klee-uclibc.bca
KLEE: NOTE: Using model: /usr/local/lib/x86_64-linux-gnu/klee/runtime/libkleeRuntimePOSIX.bca
KLEE: output directory is "/home/klee/kleeexperiment/modeltest/klee-out-11"
KLEE: Using STP solver backend
KLEE: WARNING: undefined reference to function: puts
KLEE: WARNING ONCE: calling external: syscall(16, 0, 21505, 58818256)
KLEE: WARNING ONCE: Alignment of memory from call "malloc" is not modelled. Using alignment of 8.
KLEE: WARNING ONCE: calling external: printf(55045792, 0)
result:0
result:0
result:0
result:0
result:0
result:0
result:0
KLEE: ERROR: /home/klee/kleeexperiment/modeltest/test2.c:25: external call with symbolic argument: printf
KLEE: NOTE: now ignoring this error at this location
result:0
result:0
result:0
result:0
result:0
result:0
result:0
result:0
KLEE: WARNING ONCE: calling external: puts(60211056)
yes
KLEE: ERROR: /home/klee/kleeexperiment/modeltest/test2.c:23: ASSERTION FAIL: 0
KLEE: NOTE: now ignoring this error at this location
result:9
result:0
result:-9
result:9
result:0
result:9
result:0
result:99
result:9
result:-9
result:9
yes
yes
yes
result:9
result:9
result:-9
result:9
result:-99
yes
result:99
result:99
result:99
result:999 KLEE: done: total instructions = 6381
KLEE: done: completed paths = 73
KLEE: done: generated tests = 37

可以看到结果不一样:后面比前面多生成了一个测试用例(36到37),并且新增汇报了一个error,就是assertion。为什么会多一个呢?因为:

printf放在了if(result==42)的前面。当符号值传递给printf的时候,klee可能有两种做法,一种是放弃分析,另外一种是将符号值具体化(目前我的猜测,继续往下看)。

如果是放弃分析,klee就不可能沿着该路径往后面走了;

如果是符号值具体化,klee也不可能考虑到后续有if(result==42)的语句,而故意将其具体化为42。因此,无论如何就无法检测到klee_assert的错误,即klee都不可能再对符号result添加==42的约束,从而跳入到后面的if语句中,继续符号执行。

针对该现象继续进行解释:即klee处理printf传入符号值的时候,是符号值具体化呢,还是放弃分析呢?我们就结合这个实例来探讨一下:

一,修改前和修改后的测试用例情况和路径覆盖情况对比:(说明针对一个error只产生一个测试用例)

KLEE: done: completed paths = 68

KLEE: done: generated tests = 36

KLEE: done: completed paths = 73

KLEE: done: generated tests = 37

此外,在符号执行过程中,输出了五次yes,说明有五条路径覆盖了if(result==42)。printf(“yes”)的参数不是符号值,因此可以直接执行。

现象说明:将printf从if(result==42)之前移动到之后以后,原有的68条路径中,有五条路径的约束还能够满足result==42,因此新增了五条路径(从68变为73)。

但是为什么测试用例只增加了一个呢?这是因为,五条路径都报错的话,klee只汇报一次error,同时只从产生一个覆盖该error的测试用例。

你若不信的话,我预言,你把klee_assert去掉,那么路径肯定是从68增加到73,然后测试用例也增加五个。我们试一试。

验证代码是:

修改前:

int main(int argc, char* argv[]) {

int result = argc > 1 ? atoi(argv[1]) : 0;

printf("result:%d\n",result);

if (result == 42)

{

printf("yes\n");

//klee_assert(0);

}

//printf("result:%d\n",result);

}

修改后:

int main(int argc, char* argv[]) {

int result = argc > 1 ? atoi(argv[1]) : 0;

//printf("result:%d\n",result);

if (result == 42)

{

printf("yes\n");

//klee_assert(0);

}

printf("result:%d\n",result);

}

输出信息:

  • 修改前:

klee@ubuntu:~/kleeexperiment/modeltest$ clang -I /home/klee/xiaojiework/klee/include/ -emit-llvm -c -g test2.c

klee@ubuntu:~/kleeexperiment/modeltest$ klee --libc=uclibc --posix-runtime test2.bc --sym-args 0 1 3

KLEE: NOTE: Using klee-uclibc : /usr/local/lib/x86_64-linux-gnu/klee/runtime/klee-uclibc.bca

KLEE: NOTE: Using model: /usr/local/lib/x86_64-linux-gnu/klee/runtime/libkleeRuntimePOSIX.bca

KLEE: output directory is "/home/klee/kleeexperiment/modeltest/klee-out-17"

KLEE: Using STP solver backend

KLEE: WARNING ONCE: calling external: syscall(16, 0, 21505, 47881104)

KLEE: WARNING ONCE: calling __user_main with extra arguments.

KLEE: WARNING ONCE: Alignment of memory from call "malloc" is not modelled. Using alignment of 8.

KLEE: WARNING ONCE: calling external: printf(65297728, 0)

result:0

result:0

result:0

result:0

result:0

result:0

result:0

result:0

KLEE: ERROR: /home/klee/kleeexperiment/modeltest/test2.c:19: external call with symbolic argument: printf

KLEE: NOTE: now ignoring this error at this location

result:0

result:0

result:0

result:0

result:0

result:0

result:0

result:0

result:-9

result:-9

result:0

result:0

result:-9

result:9

result:9

result:9

result:9

result:-99

result:9

result:9

result:9

result:99

result:9

result:99

result:99

result:99

result:999

KLEE: done: total instructions = 11514

KLEE: done: completed paths = 68

KLEE: done: generated tests = 36

  • 修改后:

klee@ubuntu:~/kleeexperiment/modeltest$ clang -I /home/klee/xiaojiework/klee/include/ -emit-llvm -c -g test2.c

klee@ubuntu:~/kleeexperiment/modeltest$ klee --libc=uclibc --posix-runtime test2.bc --sym-args 0 1 3

KLEE: NOTE: Using klee-uclibc : /usr/local/lib/x86_64-linux-gnu/klee/runtime/klee-uclibc.bca

KLEE: NOTE: Using model: /usr/local/lib/x86_64-linux-gnu/klee/runtime/libkleeRuntimePOSIX.bca

KLEE: output directory is "/home/klee/kleeexperiment/modeltest/klee-out-16"

KLEE: Using STP solver backend

KLEE: WARNING ONCE: calling external: syscall(16, 0, 21505, 31737040)

KLEE: WARNING ONCE: calling __user_main with extra arguments.

KLEE: WARNING ONCE: Alignment of memory from call "malloc" is not modelled. Using alignment of 8.

KLEE: WARNING ONCE: calling external: printf(44028960, 0)

result:0

result:0

result:0

result:0

result:0

KLEE: ERROR: /home/klee/kleeexperiment/modeltest/test2.c:25: external call with symbolic argument: printf

KLEE: NOTE: now ignoring this error at this location

result:0

result:0

result:0

result:0

result:0

result:0

result:0

result:0

result:0

result:-9

result:0

result:0

result:0

result:9

result:-9

result:0

result:9

result:-99

result:-9

result:9

result:9

yes

result:42

result:9

yes

result:42

result:9

result:9

yes

result:42

result:9

result:99

result:99

yes

result:42

result:99

yes

result:42

result:99

result:999

KLEE: done: total instructions = 11648

KLEE: done: completed paths = 73

KLEE: done: generated tests = 41

验证了我的推断。

问题: 为什么路径数目和测试用例不一致呢?可能是由于求解器的原因,一些路径的约束无法计算出来(继续下面看,会发现该程序不是因为这个原因。)

二、为什么路径数目和测试用例不一致呢?klee处理printf传入符号值,究竟是具体化符号值,还是直接放弃分析,报出error?

  • 进一步修改程序:
int main(int argc, char* argv[]) {
int result = argc > ? atoi(argv[]) : ;
//printf("result:%d\n",result);
if (result == )
{
printf("yes,");//修改的地方是,加了一个逗号。
klee_assert();
}
printf("result:%d\n",result);
}
  • klee符号执行结果:
klee@ubuntu:~/kleeexperiment/modeltest$ clang -I /home/klee/xiaojiework/klee/include/ -emit-llvm -c -g test2.c
klee@ubuntu:~/kleeexperiment/modeltest$ klee --libc=uclibc --posix-runtime test2.bc --sym-args 0 1 3
KLEE: NOTE: Using klee-uclibc : /usr/local/lib/x86_64-linux-gnu/klee/runtime/klee-uclibc.bca
KLEE: NOTE: Using model: /usr/local/lib/x86_64-linux-gnu/klee/runtime/libkleeRuntimePOSIX.bca
KLEE: output directory is "/home/klee/kleeexperiment/modeltest/klee-out-18"
KLEE: Using STP solver backend
KLEE: WARNING ONCE: calling external: syscall(16, 0, 21505, 75566416)
KLEE: WARNING ONCE: calling __user_main with extra arguments.
KLEE: WARNING ONCE: Alignment of memory from call "malloc" is not modelled. Using alignment of 8.
KLEE: WARNING ONCE: calling external: printf(66063584, 0)
result:0
result:0
result:0
result:0
result:0
KLEE: ERROR: /home/klee/kleeexperiment/modeltest/test2.c:25: external call with symbolic argument: printf
KLEE: NOTE: now ignoring this error at this location
result:0
result:0
result:0
result:0
result:0
result:0
result:0
result:0
result:0
result:0
result:0
result:-9
result:0
result:9
result:0
result:-9
result:9
result:-99
result:-9
result:9
KLEE: ERROR: /home/klee/kleeexperiment/modeltest/test2.c:23: ASSERTION FAIL: 0
KLEE: NOTE: now ignoring this error at this location
yes,result:9
result:9
result:9
yes,yes,result:9
result:9
result:99
result:99
yes,yes,result:99
result:99
result:999 KLEE: done: total instructions = 11623
KLEE: done: completed paths = 73
KLEE: done: generated tests = 37

首先,输出的信息都是符号执行的过程中输出的。产生的测试用例都是符号执行结束以后产生的。根据我前面的论证,当覆盖同一个错误的时候,只报一次error,只产生一个测试用例。所以,五个yes,也就说明实际能够产生测试用例的路径是41条。那么也就说明,符号执行过程中应该输出41组值。我们数一下。一共是40组值(注意,yes,单独算一组)。为什么???

这个时候我进一步摸索和修改(也是误打误撞出来)

版本一程序 版本二程序 版本三程序
int main(int argc, char* argv[]) {
int result = argc > ? atoi(argv[]) : ;
//printf("result:%d\n",result);
if (result == )
{
printf("yes,");
//klee_assert(0);
}
//printf("result:%d\n",result);
}
int main(int argc, char* argv[]) {
int result = argc > ? atoi(argv[]) : ;
//printf("result:%d\n",result);
if (result == )
{
printf("yes,");
klee_assert();
}
//printf("result:%d\n",result);
}
int main(int argc, char* argv[]) {
int result = argc > ? atoi(argv[]) : ;
printf("result:%d\n",result);
if (result == )
{
printf("yes,");
//klee_assert(0);
}
//printf("result:%d\n",result);
}

输出结果:

 版本一  版本二

版本三:

klee@ubuntu:~/kleeexperiment/modeltest$ clang -I /home/klee/xiaojiework/klee/include/ -emit-llvm -c -g test2.c
klee@ubuntu:~/kleeexperiment/modeltest$ klee --libc=uclibc --posix-runtime test2.bc --sym-args 0 1 3
KLEE: NOTE: Using klee-uclibc : /usr/local/lib/x86_64-linux-gnu/klee/runtime/klee-uclibc.bca
KLEE: NOTE: Using model: /usr/local/lib/x86_64-linux-gnu/klee/runtime/libkleeRuntimePOSIX.bca
KLEE: output directory is "/home/klee/kleeexperiment/modeltest/klee-out-21"
KLEE: Using STP solver backend
KLEE: WARNING ONCE: calling external: syscall(16, 0, 21505, 60923696)
KLEE: WARNING ONCE: calling __user_main with extra arguments.
KLEE: WARNING ONCE: Alignment of memory from call "malloc" is not modelled. Using alignment of 8.
KLEE: WARNING ONCE: calling external: printf(76818928, 0)
result:0
result:0
result:0
result:0
result:0
result:0
result:0
KLEE: ERROR: /home/klee/kleeexperiment/modeltest/test2.c:19: external call with symbolic argument: printf
KLEE: NOTE: now ignoring this error at this location
result:0
result:0
result:0
result:0
result:0
result:0
result:0
result:0
result:0
result:-9
result:9
result:0
result:0
result:-9
result:9
result:9
result:9
result:9
result:99
result:-9
result:9
result:9
result:9
result:-99
result:99
result:99
result:99
result:999 KLEE: done: total instructions = 11514
KLEE: done: completed paths = 68
KLEE: done: generated tests = 36

比较一下版本一和版本二,可以看出,版本二由于assert原因,73条路径中五条覆盖assert,所以只生成69个测试用例,汇报一次error,error对应一个测试用例。

比较一下版本二和版本三,可以看出,版本三由于printf放在了if(result==42)的前面,无论是printf传入具体值,还是printf传入符号值(符号值具体化或者klee放弃分析,见前述分析),后续覆盖if(result==42)的路径都不会被满足和分析,没有yes被输出。同时,覆盖的路径条数为68。这也说明,if点前一共有68条路径,如果没有printf影响,其中只有五条的约束在添加(result==42)以后,还能够满足,从而覆盖到if(result==42)分支内部内容。

比较一下版本一和版本三,可以看出,符号执行过程中的输出为35组数据(数一数输出的result信息的个数),但是生成了36个测试用例,报了一个error,我们看了一下,error的具体内容是:

同时配套生成了一个error的测试用例。但是符号执行过程中输出为35组数据,这也就说明了,klee处理printf传入符号值的时候,没有将其具体化以后再调用printf,而是直接报error,并且放弃分析。

这也说明了:版本三程序的一共68条路径中,有(68-35)条路径因为执行printf时传入符号值,均为error,但是只报出一个error,最后也只产生一个测试用例覆盖该条路径。这也是前述41个测试用例和40组输出数据的原因。

我们查看一下测试用例的内容和用该测试用例重新运行程序,可以看出,由于printf传入符号值的这种error类型,是klee自身不能处理的情况,而不是我们一般程序运行时的内存错误等,所以该测试用例下重新运行该程序,不会报错。result输出值为0。那为什么还要生成该测试用例呢,因为需要覆盖该error所在路径。

klee@ubuntu:~/kleeexperiment/modeltest$ export LD_LIBRARY_PATH=/home/klee/xiaojiework/klee-xiaojie/build/debug/lib/:$LD_LIBRARY_PATH
klee@ubuntu:~/kleeexperiment/modeltest$ gcc -L /home/klee/xiaojiework/klee-xiaojie/build/debug/lib/ test2.c -lkleeRuntest
klee@ubuntu:~/kleeexperiment/modeltest$ ktest-tool klee-last/test000010.ktestktest file : 'klee-last/test000010.ktest'
args : ['test2.bc', '--sym-args', '0', '1', '3']
num objects: 3
object 0: name: 'n_args'
object 0: size: 4
object 0: data: '\x01\x00\x00\x00'
object 1: name: 'arg0'
object 1: size: 4
object 1: data: '+0\x00\x00'
object 2: name: 'model_version'
object 2: size: 4
object 2: data: '\x01\x00\x00\x00'
klee@ubuntu:~/kleeexperiment/modeltest$ KTEST_FILE=klee-last/test000010.ktest ./a.out
result:0

结论性的东西往往不容易获得。分析完毕!

实验二:klee处理未建模函数和处理error的方式的更多相关文章

  1. Verilog HDL那些事_建模篇笔记(实验一,实验二)

    实验一:永远的流水灯 扫描频率配置为100Hz,即是说扫描周期为10ms.这里需要注意的是扫描周期的概念.流水灯嘛,顾名思义,扫描周期指的是流水灯扫一轮所需要的时间.听到说周期,就应该想到在建模的时候 ...

  2. 20165306 实验二 Java面向对象程序设计

    实验二 Java面向对象程序设计 实验要求 1.提交最后三个JUnit测试用例(正常情况,错误情况,边界情况)都通过的截图,截图上要有画图加水印,输入自己的学号.本提交点考查JUnit会不会使用,测试 ...

  3. C++实验二——函数重载、函数模板、简单类的定义和实现

    一.实验过程 函数重载编程练习 实验要求:编写重载函数add(),实现对int型,double型,complex型数据的加法.在main函数中定义不同类型的数据,调用测试. 代码实现: 先是简单的体验 ...

  4. 【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验二:按键模块① - 消抖

    实验二:按键模块① - 消抖 按键消抖实验可谓是经典中的经典,按键消抖实验虽曾在<建模篇>出现过,而且还惹来一堆麻烦.事实上,笔者这是在刁难各位同学,好让对方的惯性思维短路一下,但是惨遭口 ...

  5. 20145215实验二 Java面向对象程序设计

    一.实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 二.实验步骤 (一)单元测试 (1)三种代码 伪代码: ...

  6. 实验二 Java面向对象程序设计

    实验二 Java面向对象程序设计 实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计 ...

  7. 20145213《Java程序设计》实验二Java面向对象程序设计实验报告

    20145213<Java程序设计>实验二Java面向对象程序设计实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装,继承,多态 初步掌握UML建模 熟悉S.O. ...

  8. 20145206《Java程序设计》实验二Java面向对象程序设计实验报告

    20145206<Java程序设计>实验二Java面向对象程序设计实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O. ...

  9. 20145308刘昊阳 《Java程序设计》实验二 Java面向对象程序设计 实验报告

    20145308刘昊阳 <Java程序设计>实验二 Java面向对象程序设计 实验报告 实验名称 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面相对象三要素:封 ...

随机推荐

  1. 【Java并发编程】:加锁和volatile变量

    加锁和volatile变量两者之间的区别: 1.volatile变量是一种稍弱的同步机制在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比syn ...

  2. 按照Right-BICEP要求对实验二进行测试

    我的代码实现的功能很简单,在最基本的功能上,包括有无括号(0/1),有无负数(0/1),有无乘除法(0/1)验证程序的正确性,测试用例为8个,2^3个,也就覆盖了所有的代码路径. 测试计划: 基本功能 ...

  3. Android 开发工具类 29_sendPOSTRequest

    sendPOSTRequest 业务类 package com.wangjialin.internet.userInformation.service; import java.io.OutputSt ...

  4. 在Ubuntu16.04上使用Autofs

    在Solaris上,autofs是默认安装的,可以通过/net/<NFS server>很方便地访问远程的共享目录.但在Linux上(例如Fedora或者Ubuntu),使用autofs则 ...

  5. mysql RR下不存在则插入

    主要看并发事务中不存在则插入(只有key索引)的阻塞情况. 表定义: mysql> desc user; +-------------+------------------+------+--- ...

  6. video 安卓ios系统 浏览器 全屏播放以及自动播放的问题

    ios自动播放 <body onload="load()"> <div class="result_box"> <div clas ...

  7. VUE自定义指令生命周期,VUE生命周期

    一.自定义指令的生命周期 自定义指令有五个生命周期(也叫钩子函数),分别是 bind,inserted,update,componentUpdated,unbind bind:只调用一次,指令第一次绑 ...

  8. MCS锁和CLH锁

    CLH锁:自旋锁,在上一个节点上等待,先上代码: public class CLHLock { /** * 保证原子性操作 * */ private AtomicReference<Node&g ...

  9. IOS第三方之SVProgressHUD

    这个第三方和MBProgressHUD差不多,也挺简单的. // // ViewController.m // ProgressHUD // // Created by City--Online on ...

  10. 使用phpQuery轻松采集网页内容

    phpQuery是一个基于PHP的服务端开源项目,它可以让PHP开发人员轻松处理DOM文档内容,比如获取某新闻网站的头条信息.更有意思的是,它采用了jQuery的思想,你可以像使用jQuery一样处理 ...