• 实验二: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 > 1 ? atoi(argv[1]) : 0;
        printf("result:%d
    ",result);
        if (result == 42)
        {
        printf("yes
    ");
        klee_assert(0);
        }
       // printf("result:%d
    ",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 > 1 ? atoi(argv[1]) : 0;
        //printf("result:%d
    ",result);
        if (result == 42)
        {
        printf("yes
    ");
        klee_assert(0);
        }
        printf("result:%d
    ",result);
    }

    运行脚本:

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

    运行结果:

    修改前

    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 ",result);

        if (result == 42)

        {

           printf("yes ");

           //klee_assert(0);

        }

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

    }

     

    修改后:

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

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

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

        if (result == 42)

        {

           printf("yes ");

           //klee_assert(0);

        }

        printf("result:%d ",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 > 1 ? atoi(argv[1]) : 0;
        //printf("result:%d
    ",result);
        if (result == 42)
        {
        printf("yes,");//修改的地方是,加了一个逗号。
        klee_assert(0);
        }
        printf("result:%d
    ",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 > 1 ? atoi(argv[1]) : 0;
        //printf("result:%d
    ",result);
        if (result == 42)
        {
        printf("yes,");
        //klee_assert(0);
        }
        //printf("result:%d
    ",result);
    }
    int main(int argc, char* argv[]) {
        int result = argc > 1 ? atoi(argv[1]) : 0;
        //printf("result:%d
    ",result);
        if (result == 42)
        {
        printf("yes,");
        klee_assert(0);
        }
        //printf("result:%d
    ",result);
    }
    int main(int argc, char* argv[]) {
        int result = argc > 1 ? atoi(argv[1]) : 0;
        printf("result:%d
    ",result);
        if (result == 42)
        {
        printf("yes,");
        //klee_assert(0);
        }
        //printf("result:%d
    ",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: 'x01x00x00x00'
    object    1: name: 'arg0'
    object    1: size: 4
    object    1: data: '+0x00x00'
    object    2: name: 'model_version'
    object    2: size: 4
    object    2: data: 'x01x00x00x00'
    klee@ubuntu:~/kleeexperiment/modeltest$ KTEST_FILE=klee-last/test000010.ktest ./a.out
    result:0

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

  • 相关阅读:
    符号化Symbol(符号)体系
    shp2pgsql
    ArcGIS Flex(9.3)+GP服务完成最短路径分析(1)转载
    安装postgis,使用postgis导入shapefile的步骤总结 转载
    iis .NET的安装顺序反了该怎么办?
    WindowsXP 安装 PostgreSQL 8.4.2 数据库
    Web前端数据缓存处理
    SpringBoot 无Session开发
    Web端子页面iframe出现登录页面处理。
    Mybatis Generator自定义扩展
  • 原文地址:https://www.cnblogs.com/xiaojieshisilang/p/6836469.html
Copyright © 2020-2023  润新知