Hình 4 .6 là đồ thị luồng điều khiển của chương trình trên
Hình 4.3.2 .a Hàm phát sinh lỗi cập ngoài kích thước của mảng
Hình 4.3.2.b Quá trình thực thi tượng trưng của chương trình phát hiện lỗi truy cập ngoài kích thước của mảng.
Bước 2: Thực thi tượng trưng được biểu diễn bởi cây thực thi ở hình 4.3.2.c.
int main(void) {
unsigned int i, t, a[4] = { 1, 3, 5, 2 }; if (i >= 4)
exit(0);
char *p = (char *)a + i * 4; *p = *p − 1
t = a[*p]; return 0; }
int main(void) {
unsigned int i, t, a[4] = { 1, 3, 5, 2 };
Klee_make_symbolic(& i, Sizeof(i));
if (i >= 4)
exit(0);
char *p = (char *)a [ i] ;
*p = *p – 1;
return a[ *p ]
Hình 4.3.2.c. Cây thực thi tượng trưng của chương trình phát hiện lỗi truy cập ngoài kích thước của mảng.
Kết thúc giai đoạn thực thi tượng trưng thu được ba tập các ràng buộc PC2, PC11, PC12 trên các đường thực thi như sau:
PC2 = {i < 4}
PC11 = { (i < 4), (0 < i < 4)} PC12 = { (i < 4), (0 ≤ i < 4)}
Bước 3: Giai đoạn theo cả lần lượt các PC sẽ được đưa vào giải bởi công cụ giải (SMT solver), cùng với hàm đánh giá assert(a[i] = null). Hình 4.3.2.d mô tả các ràng buộc được đưa vào metaSMT.
Sau giai đoạn này 3 ca kiểm thử mà KLEE sinh ra như sau:
Ca kiểm thử 1 {i = 0 }
Ca kiểm thử 2 {i =2}
Ca kiểm thử 3 {i = 8}.
Ba ca kiểm thử này phủ toàn bộ các đường thực thi của chương trình nên độ bao phủ mã nguồn là 100%.
exit (0) EROR Index out of bounds true PC11 = { (i < 4), (0 < i < 4)} false PC2 = {i < 4} PC1 = {i < 4} true false
return a[i] return a[i]
PC12 = { (i < 4), (0 ≤ i < 4)} i ≥ 4
Hình 4.3.2.d. Cây thực thi tượng trưng của chương trình phát hiện lỗi truy cập ngoài kích thước của mảng
4.3.3. Phát hiện lỗi hàm khi đột ngột gọi hàm abort
Kiểm tra xem KLEE có phát hiện được lỗi hàm là do đột ngột gọi abort()
không. Hàm abort() trong ngôn ngữ C thuộc thư viện process.h. Khi hàm
abort() ở dòng 9 được gọi thì tất cả các công việc đang được xử lý sẽ bị hủy bỏ toàn bộ và kết thúc chương trình một cách vô điều kiện. Ở đoạn mã chương trình hình 4.3.3.a nếu nếu xâu vào là “bye!” thì câu lệnh return 0 ở dòng 11 sẽ không bao giờ được thực hiện. Do đó chương trình sẽ phát sinh lỗi.
Hình 4.3.3.a Đoạn mã nguồn có gọi hàm abort()
1. #include <string.h> 2. #include <stdlib.h>
3. int main (int argc, char * argv[]){ 5. char myStr[5];
6. int a ; // biến chứa kết quả trả về của hàm strcmp() 7. a = strcmp(myStr, "bye!")
8. klee_make_symbolic(&myStr, sizeof(myStr), "myStr"); 9. if(a== 0){
10. abort();} 11. return 0;}
{( i < 4), (0 < i < 4) , assert(a[i]= null) } SAT Test 1 UNSAT Test 2 UNSAT Test 2 1
{(i < 4), (0 < i < 4), assert(a[i]= null) } 2
{( i < 4), assert(a[i]= null) } 3
STP Z3
Boolector
Bước 1: Thực thi tượng trưng được hiện bởi cây thực thi ở hình 4.3.3.b.
Hình 4.3.3.b. Cây thực thi tượng trưng phát hiện lỗi hàm abort()
Tại bước này quá trình thực thi tượng trưng với KLEE thực hiện duyệt nhánh PC2 sau khi gặp câu lệnh return và kết thúc. Nhưng nhánh PC1 hàm abort() được gọi hàm này hủy toàn bộ các thao tác đã làm trước đó. Vì vậy, quá trình thực thi tượng trưng không thể kết thúc do chưa gặp câu lệnh return hoặc gặp lỗi.
Bước 3: Sau thời gian chờ (time out) mặc định là 2 phút, KLEE sinh được 3 ca kiểm thử sau:
Ca kiểm thử 1: Xâu vào rỗng gồm 4 kí tự kết thúc xâu "\0\0\0\0"
Ca kiểm thử 2: Xâu vào là xâu " bye!\0"
Ca kiểm thử 3: Xâu vào là kí tự a và 3 kí tự kết thúc xâu "a\0\0\0"
Bước 3: Độ bao phủ mã nguồn trong trường hợp này là nhỏ hơn 100%.
4.3.4. Sinh dữ liệu kiểm thử tự động 4.3.4. Sinh dữ liệu kiểm thử tự động 4.3.4. Sinh dữ liệu kiểm thử tự động
Cho đoạn chương trình hình 4.3.4.a
return 0 Abort failure false true PC2 = {a !=0} PC1 = {a = 0} abort() … a = 0
Hàm str_compare (string str1, string str2) để so sánh độ dài của hai xâu str1 và str2. Hàm trả về giá trị 1 khi hai xâu này bằng nhau và trả về 0 trong trường hợp ngược lại.