Skip to content
Snippets Groups Projects
Select Git revision
  • 7f2de6c9f85fa9978acf16167f90f6427f04635a
  • master default protected
  • home_exam
  • wip
4 results

main5.rs

Blame
  • get_sign.c 6.57 KiB
    /*
     * First KLEE tutorial: testing a small function
     * https://klee.github.io/tutorials/testing-function/
     */
    
    #include <klee/klee.h>
    
    int get_sign(int x)
    {
        if (x == 0)
            return 0;
    
        if (x < 0)
            return -1;
        else
            return 1;
    }
    
    int main()
    {
        int a;
        klee_make_symbolic(&a, sizeof(a), "a");
        return get_sign(a);
    }
    
    // A) Compiling into LLVM bitcode
    // > clang -emit-llvm -c get_sign.c
    //
    // Now you can run Klee on your generated bitcode.
    //
    // > klee get_sign.bc
    //
    // [your answer here]
    // KLEE: Using Z3 solver backend
    // 
    // KLEE: done: total instructions = 31
    // KLEE: done: completed paths = 3
    // KLEE: done: generated tests = 3
    // 
    //
    // B) Inspecting the output
    //
    // > ls klee-last/
    //
    // [your answer here]
    // assembly.ll  info  messages.txt  run.istats  run.stats
    // test000001.ktest  test000002.ktest  test000003.ktest  warnings.txt
    //
    // C) Inspecting the generated test cases
    //
    // > ktest-tool klee-last/test000001.ktest
    //
    // What path in the code does this test represent?
    //
    // [your answer here]
    // ktest file : 'klee-last/test000001.ktest'
    // args       : ['get_sign.bc']
    // num objects: 1
    // object 0: name: 'a'
    // object 0: size: 4
    // object 0: data: b'\x00\x00\x00\x00'
    // object 0: hex : 0x00000000
    // object 0: int : 0
    // object 0: uint: 0
    // object 0: text: ....
    //
    // It represent the path where x = 0 and the return value is 0.
    // 
    //
    // > ktest-tool klee-last/test000002.ktest
    //
    // What path in the code does this test represent?
    //
    // [your answer here]
    // ktest file : 'klee-last/test000002.ktest'
    // args       : ['get_sign.bc']
    // num objects: 1
    // object 0: name: 'a'
    // object 0: size: 4
    // object 0: data: b'\x01\x01\x01\x01'
    // object 0: hex : 0x01010101
    // object 0: int : 16843009
    // object 0: uint: 16843009
    // object 0: text: ....
    //
    // It represent the path where x > 0 and the return value is 1.
    //
    //
    // > ktest-tool klee-last/test000003.ktest
    //
    // What path in the code does this test represent?
    //
    // [your answer here]
    // ktest file : 'klee-last/test000003.ktest'
    // args       : ['get_sign.bc']
    // num objects: 1
    // object 0: name: 'a'
    // object 0: size: 4
    // object 0: data: b'\x02\x01\x01\x80'
    // object 0: hex : 0x02010180
    // object 0: int : -2147417854
    // object 0: uint: 2147549442
    // object 0: text: ....
    //
    // It represent the path where x < 0 and the return value is -1.
    //
    //
    // D) Replaying a test case
    //
    // Fist check that includes were installed:
    // > ls /usr/local/include
    // klee
    //
    // > ls /usr/local/lib
    // klee  libkleeRuntest.so  libkleeRuntest.so.1.0
    //
    // If you installed Klee using the package manager
    // the path might be different:
    //
    // Using `aur` (arch) files are stored in the system default
    // folders, `/usr/include` and `/usr/lib`.
    //
    // If those are ok, then you can compile for replay:
    //
    // > clang -I /usr/local/include/ -L /usr/local/lib get_sign.c -l kleeRuntest
    //
    // Or just
    // > clang get_sign -l kleeRuntest
    //
    // If the `include` and `lib` paths are the system defaults.
    //
    // To replay the first test:
    //
    // We need to add the libary path so it can be dynamically loaded:
    // Depending on shell this might look different:
    //
    // Under `bash` (and `bash` like shells)
    // > export LD_LIBRARY_PATH=/usr/local/lib/:$LD_LIBRARY_PATH
    //
    // Under `fish`
    // > set -x LD_LIBRARY_PATH /usr/local/lib/:$LD_LIBRARY_PATH
    //
    // Once again, if using the system default system folders
    // you don't need to add anything to `LD_LIBRARY_PATH`.
    //
    // > KTEST_FILE=klee-last/test000001.ktest ./a.out
    //
    // Now let's inspect the status (return code), in `bash`:
    // $? is the return value (error code) as seen by the shell.
    //
    // > echo $?
    //
    // In `fish` you would do
    //
    // > echo $status
    //
    // Did the result correspond to the expected path for the test?
    //
    // [your answer here]
    // yes
    // echo $?  gives  0
    //
    // > KTEST_FILE=klee-last/test000002.ktest ./a.out
    //
    // Inspect the return code:
    //
    // Did the result correspond to the expected path for the test?
    //
    // [your answer here]
    // Yes
    // echo $?  gives  1
    //
    // > KTEST_FILE=klee-last/test000003.ktest ./a.out
    //
    // Inspect the return code:
    //
    // Did the result correspond to the expected path for the test?
    //
    // [your answer here]
    // Yes
    // echo $?  gives 255 (which is equal to -1 of 8 signed bits)
    //
    // Why not? Confer to shell error codes:
    //
    // [your answer here]
    // ??? TODO
    //
    // D) Debugging
    //
    // In the above example its kind of hard to see exactly
    // what happens. Using `gdb` you single step the program.
    //
    // First build it with debug symbols (`-g`).
    // > clang -g -I /usr/local/include/ -L /usr/local/lib get_sign.c -l kleeRuntest
    //
    // Or if using system defaults:
    // > clang -g get_sign.c -l kleeRuntest
    //
    // Then start `gdb`:
    // > KTEST_FILE=klee-last/test000001.ktest gdb ./a.out
    // (gdb) break get_sign
    //
    // (gdb) run
    //
    // Now we can inspect the `x` argument by:
    // (gdb) print x
    //
    // What value do you get, and why?
    //
    // [your answer here]
    // (gdb) print x
    // $1 = 0
    // It has the value 0 and it got that because the constraint x == o is the fist split in the paths. 
    //
    // Step the code
    // > (gdb) next
    //
    // What path did it take, and why?
    //
    // [your answer here]
    // Breakpoint 1, get_sign (x=0) at get_sign.c:10
    // 10	    if (x == 0)
    // (gdb) next
    // 11	        return 0;
    // It took the path where it returns 0.
    // It took that path because x = 0 thus x == 0.
    //
    // Now we can try with another test:
    //
    // (gdb) set environment KTEST_FILE=klee-last/test000002.ktest
    //
    // And (re-start) the debug session:
    // (gdb) run
    //
    // Step through the code.
    //
    // Which path did it take, and why?
    //
    // [your answer here]
    // Breakpoint 1, get_sign (x=16843009) at get_sign.c:10
    // 10	    if (x == 0)
    // (gdb) next
    // 13	    if (x < 0)
    // (gdb) next
    // 16	        return 1;
    // It took the path where it returns 1.
    // It took that path because x = 16843009 thus x != 0 and x !< 0.
    //
    //
    // And finally:
    //
    // (gdb) set environment KTEST_FILE=klee-last/test000003.ktest
    //
    // Which path did it take, and why?
    //
    // [your answer here]
    // Breakpoint 1, get_sign (x=-2147417854) at get_sign.c:10
    // 10	    if (x == 0)
    // (gdb) next
    // 13	    if (x < 0)
    // (gdb) next
    // 14	        return -1;
    // It took the path where it returns -1.
    // It took that path because x = -2147417854 thus x != 0 and x < 0.
    //
    // E) Under the hood.
    //
    // Explain in your own words how
    // `klee_make_symbolic(&a, sizeof(a), "a");`
    // works when you run `klee` to generate test cases:
    //
    // [your answer here]
    // (hint, mark memory region as symbolic)
    //
    // Explain in your own words how
    // `klee_make_symbolic(&a, sizeof(a), "a");`
    // works when you replay test cases:
    //
    // [your answer here]
    // (hint, KTEST_FILE points to a concrete assignment
    // of the memory region)