250 likes | 355 Vues
This paper presents a static analysis tool designed to identify buffer overrun errors in C programs without executing any tests. The tool, called Airac, ensures comprehensive analysis by covering all potential states in a program's execution. Utilizing techniques such as sound design through abstract interpretation, flow sensitivity, and static inlining, Airac improves accuracy while minimizing costs through efficient operations. The effectiveness of the analyzer is demonstrated through practical examples, showcasing its ability to identify errors and provide insight into program correctness.
E N D
Analyzer for MPSoC Project Yungbum Jung, Jaehwang Kim, Jaeho Shin, Kwangkeun Yi Programming Research Lab. Seoul National University 7/12/2005@MPSOC Project Workshop
AiracStatic Analyzer for Detecting All Buffer Overrun Errors in C Programs • “static”: no test runs • “all”: no un-noticed overruns • “C”: full ANSI C + (GNU C) int *c = (int *)malloc(sizeof(int)*10); c[i] = 1; c[i + f()] = 1; c[*k + (*g)()] = 1; x = c+5; x[1] = 1; z->a = c; (z->a)[i] = 1; foo(c+2); int foo(int *d) {…d[i] = 1; …}
Airac: internals x1 = F1(x1,…,xN) x2 = F2(x1,…,xN) … xN = FN(x1,…,xN) C files equation solver C’ files bug identification
Technologies in Airac • sound design by abstract interpretation • accuracy improvement by • narrowing, flow-sensitivity, context pruning, static inlining(bounded polyvariance), static loop unrolling • cost reduction by • widening, economic join/partial-order operations • careful worklist order: lazy at join points
Finite Approximation struct node {int x[10]; node *next;}; x = (node *)malloc(sizeof(node)); x->next = NULL; for (i=0;;i++) { y = (node *)malloc(sizeof(node)); y->next = NULL; x->next = y; x = y; } … y x ArrayPtr = Base x Offset x Size Offset = Size = Interval x y
Caveats • soundness • typeful C programs • array sizes remain the same as declared • no semantics for error behavior (e.g. overrun, null deref.) • no semantics for completely unknown buffers • no main() then • analyzing procedure calls in their defined order • alarms • not for completely unknown buffers
Airac: performance (1/3)(commercial softwares) 3.2GHz P4, 4GB RAM
Airac vsSwat(2/2) Airac Bugs Coverity
cdc_acm.c (Linux device driver)
How to Analyze • We collect state at the each program point following semantics of a C program • We must cover all states of program
Example int main() { int i=10; int (*farr[])(int)={incr,decr,incr}; body(farr,i); return 0; } static int incr(int i) { return i+1; } static int decr(int i) { return i-1; } int body(int (*farr[])(int), int i) { int arr[10]; int idx = rand() % 3; int num = farr[idx](i); printf(“num=%d\n”, num); if (num >= 0) then return arr[num]; else body(farr, num); } idx ! [0, 2] Result: array index out of bound at (file: "test/fptr.c", line: 20, column: 21) Array name: arr Overflow (array index: [9, 11], array size: [10, 10])
Fixpoint Algorithm int A[10]; int i; int num = 10; for (i=0; i<num; i++) { A[i] = i; } A[i] = 10; start num [10, 10] i=0; i [0, 0] i<num; i [0, 0] i [0, 1] A[i] = i; i [1, 1] i [1, 2] A[0] [0, 0] A[1] [0, 1] A[0] [0, 1] i++;
Fixpoint Algorithm int A[10]; int i; int num = 10; for (i=0; i<num; i++) { A[i] = i; } A[i] = 10; start num [10, 10] i=0; i [0, 0] i<num; i [10, 10] i [0, 9] A[i] = 10; i [1, 10] A[i] = i; A[0] [0, 9] A[9] [0, 9] end i++;
Fixpoint Algorithm With Widening int A[10]; int i; int num = rand(); for (i=0; i<num; i++) { A[i] = i; } A[i] = 10; start num [-1, +1] i=0; i [0, 0] i<num; i [0, 0] i [0, 1] i [0, 0] i [0, 1] A[i] = 10; A[i] = i; i [1, 2] i [1, 1] A[0] [10, 10] A[0] [10, 10] A[1] [10, 10] A[0] [0, 0] A[1] [0, 1] A[0] [0, 1] end i++;
Fixpoint Algorithm With Widening int A[10]; int i; int num = rand(); for (i=0; i<num; i++) { A[i] = i; } A[i] = 10; start num [-1, +1] i=0; i [0,0] i<num; i [0, 1] i [0,+1] i [0,+1] i [1,+1] A[i] = 10; A[i] = i; A[0] [0, +1] A[9] [0, +1] A[0] [0,+1] A[9] [0,+1] A[0] [10,10] A[1] [10,10] end i++;
cdc_acm.c (Linux device driver)
Better than Airac • faster and more accurate • Implemented with • trace partitioning • error explanation • stack removal • code for open-source
Trace Partitioning main(void) { int arr[10]; int *p = (int *)malloc(sizeof(int)*10); int n, k; scanf(“Type an integer:\n”,&n); if(n <10 && n >=0){ k = 1; arr[n] = n; } else { k = 0; *(p + n)= 10; } if(k){ p[n] = 10; false alarm! } } start num=readInput(); n [-1,+1] n? n [0,9] n [-1,+1] k=1; k=0; k [1,1] k [0,0] arr[n]=n; *(p+n)=10; n [-1,+1] k? k [0,1] p[n]=10; end
Trace Partitioning main(void) { int arr[10]; int *p = (int *)malloc(sizeof(int)*10); int n, k; scanf(“Type an integer:\n”,&n); if(n <10 && n >=0){ k = 1; arr[n] = n; } else { k = 0; *(p + n)= 10; } if(k){ p[n] = 10; } } start num=readInput(); n [-1,+1] n? n [0,9] n [-1,+1] k=1; k=0; k [1,1] k [0,0] arr[n]=n; *(p+n)=10; k? k? p[n]=10; end end
Error Explanation int str_length = 2; inline void double_length() { str_length <<= 1; /* index참조에 사용된 변수값이 변한 지점 */ } static void get_string(char *string) { int counter; for (counter = 0; counter < str_length; counter++) { ...... } double_length(); /* index참조에 사용된 변수값이 변한 호출 */ string[str_length-1] = '\0'; /* Index: [3, 3] */ ...... } main(void) { ...... char *device_string = (char*) malloc(sizeof(char) * str_length); /* alarm이 발생한 buffer가 선언된 지점 */ get_string(device_string); /* alarm이 발생한 호출 */ ...... }
Thank you ropas.snu.ac.kr/airac