实验二:klee处理未建模函数和处理error的方式
首先,能够分析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,然后测试用例也增加五个。我们试一试。 验证代码是:
输出信息:
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 main(int argc, char* argv[]) { |
int main(int argc, char* argv[]) { |
输出结果:
版本一 | 版本二 |
![]() |
![]() |
版本三:
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的方式的更多相关文章
- Verilog HDL那些事_建模篇笔记(实验一,实验二)
实验一:永远的流水灯 扫描频率配置为100Hz,即是说扫描周期为10ms.这里需要注意的是扫描周期的概念.流水灯嘛,顾名思义,扫描周期指的是流水灯扫一轮所需要的时间.听到说周期,就应该想到在建模的时候 ...
- 20165306 实验二 Java面向对象程序设计
实验二 Java面向对象程序设计 实验要求 1.提交最后三个JUnit测试用例(正常情况,错误情况,边界情况)都通过的截图,截图上要有画图加水印,输入自己的学号.本提交点考查JUnit会不会使用,测试 ...
- C++实验二——函数重载、函数模板、简单类的定义和实现
一.实验过程 函数重载编程练习 实验要求:编写重载函数add(),实现对int型,double型,complex型数据的加法.在main函数中定义不同类型的数据,调用测试. 代码实现: 先是简单的体验 ...
- 【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验二:按键模块① - 消抖
实验二:按键模块① - 消抖 按键消抖实验可谓是经典中的经典,按键消抖实验虽曾在<建模篇>出现过,而且还惹来一堆麻烦.事实上,笔者这是在刁难各位同学,好让对方的惯性思维短路一下,但是惨遭口 ...
- 20145215实验二 Java面向对象程序设计
一.实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 二.实验步骤 (一)单元测试 (1)三种代码 伪代码: ...
- 实验二 Java面向对象程序设计
实验二 Java面向对象程序设计 实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计 ...
- 20145213《Java程序设计》实验二Java面向对象程序设计实验报告
20145213<Java程序设计>实验二Java面向对象程序设计实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装,继承,多态 初步掌握UML建模 熟悉S.O. ...
- 20145206《Java程序设计》实验二Java面向对象程序设计实验报告
20145206<Java程序设计>实验二Java面向对象程序设计实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O. ...
- 20145308刘昊阳 《Java程序设计》实验二 Java面向对象程序设计 实验报告
20145308刘昊阳 <Java程序设计>实验二 Java面向对象程序设计 实验报告 实验名称 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面相对象三要素:封 ...
随机推荐
- C++ 实现Biginteger
网上C++版Biginteger参差不齐,一下子没有找到一个令人满意Biginteger,最近用c++改写了一下C#版 BigInteger,可以用于RSA大素数的生成,分享给大家.也请大家批评指正改 ...
- Impala配置HA-Nginx
Impala的高可用配置,官方的例子用的是Haproxy,考虑到nginx配置简单,使用人群广泛,再加上nginx1.9以后支持TCP的负载均衡,所以选用nginx. nginx安装:yum inst ...
- mybatis异常:Error instantiating class com.psc.bean.User with invalid types () or values ().
Error instantiating class com.psc.bean.User with invalid types () or values (). 是由于bean类没有无参构建方法,添加一 ...
- 数据库-转换sql语句
文章描述:主要说明转换成SQL语句的过程.----必要信息(数据库名,表名,条件)转换成SQL语句 一些界面上数据增删改查的操作往往只需要输入一数据库名,表名,加条件就可以进行数据查询了,在这背后是怎 ...
- Boosting和Bagging的异同
二者都是集成学习算法,都是将多个弱学习器组合成强学习器的方法. 1.Bagging (主要关注降低方差) Bagging即套袋法,其算法过程如下: A)从原始样本集中抽取训练集.每轮从原始样本集中使用 ...
- NLP Attention
一.概述 自动摘要可以从很多角度进行分类,例如单文档摘要/多文档摘要.单语言摘要/跨语言摘要等.从技术上说,普遍可以分为三类: i. 抽取式摘要(extractive),直接从原文中抽取一些句子组成摘 ...
- springMVC实现json
很多时候前端都需要调用后台服务实现交互功能,常见的数据交换格式多是JSON或XML,这里主要讲解Spring MVC为前端提供JSON格式的数据并实现与前台交互. 一.概要 JSON(JavaScri ...
- <MYSQL Index>
About Mysql 1. Mysql工作流程分析 2. Mysql单实例安装(5.6.31) DATABASE 1. 事务的4种隔离级别 ——————————————————Mysql管理———— ...
- input属性type为file打开文件资源管理器时,如何限制多次选取或只能一次选取的行为
1.input标签没有设置multiple属性,文件资源管理器默认一次选取 <!doctype html> <html lang="en"> <hea ...
- Hive集成HBase实践
#step1: create hive table 't_test' hive -e "create table test.t_user(id int,name string,age int ...