CNUproject/코드 동일성 검사 도구

23_IR에 Klee 함수 호출 직접 추가

YUMMMM 2023. 10. 19. 20:10

IR에 KLEE 함수 호출 코드 직접 삽입하는 것이 제대로 작동하지 않는지 확인

 

1. if문이 있는 코드, if의 조건이 하나만 만족하도록 하여 그때의 테스트 케이스만 생성하는지 확인

 

#include <stdio.h>

int get_sign(int x) {
	if (x == 0)
		return 0;
	
	else if (x < 0)
		return -1;
	else
		return 1;
}

int main() {
	int a;
	get_sign(a);
	return 0;
}
; ModuleID = 'testKlee.c'
source_filename = "testKlee.c"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "arm64-apple-macosx13.0.0"

@.str = private unnamed_addr constant [2 x i8] c"a\00", align 1

; Function Attrs: noinline nounwind optnone ssp uwtable
define dso_local i32 @get_sign(i32 %0) #0 {
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  store i32 %0, i32* %3, align 4
  %4 = load i32, i32* %3, align 4
  %5 = icmp eq i32 %4, 0
  br i1 %5, label %6, label %7

6:                                                ; preds = %1
  store i32 0, i32* %2, align 4
  br label %12

7:                                                ; preds = %1
  %8 = load i32, i32* %3, align 4
  %9 = icmp slt i32 %8, 0
  br i1 %9, label %10, label %11

10:                                               ; preds = %7
  store i32 -1, i32* %2, align 4
  br label %12

11:                                               ; preds = %7
  store i32 1, i32* %2, align 4
  br label %12

12:                                               ; preds = %11, %10, %6
  %13 = load i32, i32* %2, align 4
  ret i32 %13
}

; Function Attrs: noinline nounwind optnone ssp uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4

  %symbol = bitcast i32* %2 to i8*
  call void @klee_make_symbolic(i8* %symbol, i64 4, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i64 0, i64 0))
  
  %symbol.ass = load i32, i32* %2, align 4
  %cmp = icmp sgt i32 %symbol.ass, 0
  %conv = zext i1 %cmp to i32
  %conv1 = sext i32 %conv to i64
  call void @klee_assume(i64 %conv1)

  %3 = load i32, i32* %2, align 4
  %4 = call i32 @get_sign(i32 %3)


  ret i32 0
}

declare dso_local void @klee_make_symbolic(i8*, i64, i8*)

declare dso_local void @klee_assume(i64)

attributes #0 = { noinline nounwind optnone ssp uwtable "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-a12" "target-features"="+aes,+crc,+crypto,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.3a,+zcm,+zcz" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
!llvm.ident = !{!6}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 1, !"branch-target-enforcement", i32 0}
!2 = !{i32 1, !"sign-return-address", i32 0}
!3 = !{i32 1, !"sign-return-address-all", i32 0}
!4 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!5 = !{i32 7, !"PIC Level", i32 2}
!6 = !{!"Homebrew clang version 12.0.1"}

main에서 a를 klee_make_symbolic으로 전달하고, a가 0보다 크다는 조건을 klee_assume에 전달하는 IR 추가

 

 

KLEE 실행시

a가 양수일 때의 테스트 케이스만 생성하는 것으로 보아 klee 함수를 호출하는 IR을 삽입한 것이 잘 동작하는 것을 알 수 있음

 

 

2. 지금껏 해오던 코드에서 결과값이 같지 않다는 조건 대신 같다는 조건을 넣었을 때 Provably false 에러 없이 잘 작동하는지 확인

#include <stdio.h>

int addResult;
int mulResult;

int addNum(int num) {
	num += num;
	return num;
}

int mulNum(int num) {
	num *= 2;
	return num;
}

int main() {
	int num;
	addResult = addNum(num);
	mulResult = mulNum(num);

	return 0;
}
; ModuleID = 'test3.c'
source_filename = "test3.c"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "arm64-apple-macosx13.0.0"

@.str = private unnamed_addr constant [5 x i8] c"num1\00", align 1
@.str.1 = private unnamed_addr constant [5 x i8] c"num2\00", align 1

@addResult = dso_local global i32 0, align 4
@mulResult = dso_local global i32 0, align 4

; Function Attrs: noinline nounwind optnone ssp uwtable
define dso_local i32 @addNum(i32 %0) #0 {
  %num = alloca i32, align 4
  store i32 %0, i32* %num, align 4
  %num.addr = bitcast i32* %num to i8*
  call void @klee_make_symbolic(i8* %num.addr, i64 4, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0))

  %2 = alloca i32, align 4
  store i32 %0, i32* %2, align 4
  %3 = load i32, i32* %2, align 4
  %4 = load i32, i32* %2, align 4
  %5 = add nsw i32 %4, %3
  store i32 %5, i32* %2, align 4
  %6 = load i32, i32* %2, align 4
  ret i32 %6
}

declare dso_local void @klee_make_symbolic(i8*, i64, i8*)

; Function Attrs: noinline nounwind optnone ssp uwtable
define dso_local i32 @mulNum(i32 %0) #0 {
  %num = alloca i32, align 4
  store i32 %0, i32* %num, align 4
  %num.addr = bitcast i32* %num to i8*
  call void @klee_make_symbolic(i8* %num.addr, i64 4, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0))
  
  %2 = alloca i32, align 4
  store i32 %0, i32* %2, align 4
  %3 = load i32, i32* %2, align 4
  %4 = mul nsw i32 %3, 2
  store i32 %4, i32* %2, align 4
  %5 = load i32, i32* %2, align 4
  ret i32 %5
}


; Function Attrs: noinline nounwind optnone ssp uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  %3 = load i32, i32* %2, align 4
  %4 = call i32 @addNum(i32 %3)
  store i32 %4, i32* @addResult, align 4
  %5 = load i32, i32* %2, align 4
  %6 = call i32 @mulNum(i32 %5)
  store i32 %6, i32* @mulResult, align 4

  %7 = load i32, i32* @addResult, align 4
  %8 = load i32, i32* @mulResult, align 4
  
  ; klee_assume 함수 호출
  %cmp = icmp eq i32 %7, %8
  %conv = zext i1 %cmp to i32
  %conv2 = sext i32 %conv to i64
  call void @klee_assume(i64 %conv2)

  ret i32 0
}

declare dso_local void @klee_assume(i64)

attributes #0 = { noinline nounwind optnone ssp uwtable "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-a12" "target-features"="+aes,+crc,+crypto,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.3a,+zcm,+zcz" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
!llvm.ident = !{!6}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 1, !"branch-target-enforcement", i32 0}
!2 = !{i32 1, !"sign-return-address", i32 0}
!3 = !{i32 1, !"sign-return-address-all", i32 0}
!4 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!5 = !{i32 7, !"PIC Level", i32 2}
!6 = !{!"Homebrew clang version 12.0.1"}

main에서 add와 mul 함수의 결과값이 서로 같다는 조건을 klee_assume에 전달하는 IR 추가

 

KLEE 실행시

Provably false 없이 정상 작동하는 것을 알 수 있음

 

3. num을 글로벌 변수로 생성하고, main에서 한 번만 Symbolic 변수로 생성

#include <stdio.h>

int num;

int addNum(int num) {
        num += num;
        return num;
}

int mulNum(int num) {
        num *= 2;
        return num;
}

int main() {
        int add = addNum(num);
        int mul = mulNum(num);

        return 0;
}
; ModuleID = 'test4.c'
source_filename = "test4.c"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "arm64-apple-macosx13.0.0"

@num = dso_local global i32 0, align 4
@.str = private unnamed_addr constant [4 x i8] c"num\00", align 1

; Function Attrs: noinline nounwind optnone ssp uwtable
define dso_local i32 @addNum(i32 %0) #0 {
  %2 = alloca i32, align 4
  store i32 %0, i32* %2, align 4
  %3 = load i32, i32* %2, align 4
  %4 = load i32, i32* %2, align 4
  %5 = add nsw i32 %4, %3
  store i32 %5, i32* %2, align 4
  %6 = load i32, i32* %2, align 4
  ret i32 %6
}

; Function Attrs: noinline nounwind optnone ssp uwtable
define dso_local i32 @mulNum(i32 %0) #0 {
  %2 = alloca i32, align 4
  store i32 %0, i32* %2, align 4
  %3 = load i32, i32* %2, align 4
  %4 = mul nsw i32 %3, 2
  store i32 %4, i32* %2, align 4
  %5 = load i32, i32* %2, align 4
  ret i32 %5
}

; Function Attrs: noinline nounwind optnone ssp uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %symbol = bitcast i32* @num to i8*
  call void @klee_make_symbolic(i8* %symbol, i64 4, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0))

  store i32 0, i32* %1, align 4
  %4 = load i32, i32* @num, align 4
  %5 = call i32 @addNum(i32 %4)
  store i32 %5, i32* %2, align 4
  %6 = load i32, i32* @num, align 4
  %7 = call i32 @mulNum(i32 %6)
  store i32 %7, i32* %3, align 4

  %8 = load i32, i32* %2, align 4
  %9 = load i32, i32* %3, align 4
  %cmp = icmp ne i32 %8, %9
  %conv = zext i1 %cmp to i32
  %conv2 = sext i32 %conv to i64
  call void @klee_assume(i64 %conv2)
  ret i32 0
}

declare dso_local void @klee_make_symbolic(i8*, i64, i8*)

declare dso_local void @klee_assume(i64)

attributes #0 = { noinline nounwind optnone ssp uwtable "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-a12" "target-features"="+aes,+crc,+crypto,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.3a,+zcm,+zcz" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
!llvm.ident = !{!6}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 1, !"branch-target-enforcement", i32 0}
!2 = !{i32 1, !"sign-return-address", i32 0}
!3 = !{i32 1, !"sign-return-address-all", i32 0}
!4 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!5 = !{i32 7, !"PIC Level", i32 2}
!6 = !{!"Homebrew clang version 12.0.1"}

main에서 함수 호출 전에 글로벌 변수 num을 klee_make_symbolic으로 전달하는 IR 추가

각 함수의 결과값이 같지 않다는 조건을 klee_assume으로 전달하는 IR 추가

 

 

KLEE 실행시

Provably false 에러 발생


IR에 KLEE 함수를 호출하는 코드를 직접 삽입해도 문제가 없는 것으로 확인됨