klee / klee

KLEE Symbolic Execution Engine

Home Page:https://klee-se.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Issue in generating paths in KLEE

karthiv opened this issue · comments

The program given here should generate 3 paths - it does so in klee web(http://klee.doc.ic.ac.uk/) but in klee installation (llvm-3.8 as well as current docker image) it generates only 2 paths and 2 testcases.

On analysing the path where k=10 is not being explored by klee.

However, if I uncomment the lines - printf-1,2,3 - It generates 3 paths.
Why the path k=10 not being explored in klee installation and docker image?

Program under test:

#include <klee/klee.h>
#include <stdio.h>
int main () {
int a,b;
klee_make_symbolic(&a, sizeof(a),"a");
klee_make_symbolic(&b, sizeof(b),"b");
int k=0;
if(a==b){
k=5;
//printf("%s","a==b"); //printf-1
if(a>5){
k=10;
//printf("%s","a>5"); // printf-2
}
}
//printf("%s","return"); //printf-3
printf("%d",k);
return 0;
}

When you comment out the printf calls, the bitcode gets optimised and you end up with a different code structure.

In the optimised case the store to k is handled solely via a select instruction (single path in KLEE) without a branch:

if.then:
  store i32 5, i32* %k
  %7 = load i32, i32* %a
  %cmp1 = icmp sgt i32 %7, 5
  %spec.store.select = select i1 %cmp1, i32 10, i32 5  <--- here
  store i32 %spec.store.select, i32* %k, align 4
  br label %if.end3

whereas in the unoptimised case you get the expected branch and the assignment in two basic blocks:

if.then:
  store i32 5, i32* %k, align 4  <--- here
  %call = call i32 (i8*, ...) @printf(...)
  %7 = load i32, i32* %a, align 4
  %cmp1 = icmp sgt i32 %7, 5
  br i1 %cmp1, label %if.then2, label %if.end4

if.then2:
  store i32 10, i32* %k, align 4  <--- here
  ...

When you comment out the printf calls, the bitcode gets optimised and you end up with a different code structure.

In the optimised case the store to k is handled solely via a select instruction (single path in KLEE) without a branch:

if.then:
  store i32 5, i32* %k
  %7 = load i32, i32* %a
  %cmp1 = icmp sgt i32 %7, 5
  %spec.store.select = select i1 %cmp1, i32 10, i32 5  <--- here
  store i32 %spec.store.select, i32* %k, align 4
  br label %if.end3

whereas in the unoptimised case you get the expected branch and the assignment in two basic blocks:

if.then:
  store i32 5, i32* %k, align 4  <--- here
  %call = call i32 (i8*, ...) @printf(...)
  %7 = load i32, i32* %a, align 4
  %cmp1 = icmp sgt i32 %7, 5
  br i1 %cmp1, label %if.then2, label %if.end4

if.then2:
  store i32 10, i32* %k, align 4  <--- here
  ...

Thank you for the answer. How to remove optimization in klee installed version and docker?

I printed the CFG, it does not optimize the code as you have mentioned . The assembly code generates is

`define i32 @main() #0 !dbg !4 {
%1 = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
%k = alloca i32, align 4
store i32 0, i32* %1, align 4
call void @llvm.dbg.declare(metadata i32* %a, metadata !11, metadata !12), !dbg !13
call void @llvm.dbg.declare(metadata i32* %b, metadata !14, metadata !12), !dbg !15
%2 = bitcast i32* %a to i8*, !dbg !16
call void @klee_make_symbolic(i8* %2, i64 4, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i32 0, i32 0)), !dbg !17
%3 = bitcast i32* %b to i8*, !dbg !18
call void @klee_make_symbolic(i8* %3, i64 4, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0)), !dbg !19
call void @llvm.dbg.declare(metadata i32* %k, metadata !20, metadata !12), !dbg !21
store i32 0, i32* %k, align 4, !dbg !21
%4 = load i32, i32* %a, align 4, !dbg !22
%5 = load i32, i32* %b, align 4, !dbg !24
%6 = icmp eq i32 %4, %5, !dbg !25
br i1 %6, label %7, label %10, !dbg !26

; :7 ; preds = %0
store i32 5, i32* %k, align 4, !dbg !27
%8 = load i32, i32* %a, align 4, !dbg !29
%9 = icmp sgt i32 %8, 5, !dbg !31
%. = select i1 %9, i32 10, i32 5, !dbg !32
store i32 %., i32* %k, align 4, !dbg !33
br label %10, !dbg !35

; :10 ; preds = %7, %0
ret i32 0, !dbg !36
}`

  • I have attached screenshot here

Screenshot from 2023-02-18 00-07-57

I'm afraid you have to remove that line and recompile KLEE. KLEE runs some passes on the bitcode before execution. The final bitcode file can be found in klee-last/assembly.ll and should show the differences I described above.

Edit: When you're using newer LLVM versions, it should be sufficient to compile your bitcode file with -O0 to annotate the functions with optnone.

I'm afraid you have to remove that line and recompile KLEE. KLEE runs some passes on the bitcode before execution. The final bitcode file can be found in klee-last/assembly.ll and should show the differences I described above.

Edit: When you're using newer LLVM versions, it should be sufficient to compile your bitcode file with -O0 to annotate the functions with optnone.

Thank you! The issue is resolved

I added the following statement into the program under test and the results matched with klee web

#pragma clang optimize off

My LLVM version is 3.8 and Klee version is 2.1-pre

My LLVM version is 3.8 and Klee version is 2.1-pre

That LLVM version is almost 7 years old and even your KLEE version is really outdated. You might want to consider updating.