Slide 1

Slide 1 text

1 / 23 Making Bounded Model Checking Interprocedural in (Static Analysis) Style Daniil Stepanov, Marat Akhin, and Mikhail Belyaev Saint Petersburg Polytechnic University, Russia Jetbrains Research, Russia Novemver 9, 2019

Slide 2

Slide 2 text

2 / 23 Static analysis Static program analysis is the analysis of computer software which is performed without actually executing programs

Slide 3

Slide 3 text

3 / 23 Interprocedural analysis One of the hardest problems in BMC is interprocedural analysis Standard approach is function inlining An alternative to function inlining is context-sensitive analyses

Slide 4

Slide 4 text

4 / 23 Related work Craig interpolant for an inconsistent pair of formulas (B, Q) is a formula I such that: • B → I • (I, Q) is also an inconsistent pair of formulae • I contains only uninterpreted symbols common to B and Q External specications • specialized annotation comments • embedded domain-specic language (DSL) • external DSL Another tools: • Saturn - function summaries

Slide 5

Slide 5 text

5 / 23 Bounded model checking algorithm

Slide 6

Slide 6 text

6 / 23 Verication example Program: int x; int y=8,z=0,w=0; if (x) z = y - 1; else w = y + 1; assert (z == 7 || w == 9) Constraints: y = 8, z = x ? y -1 : 0, w = x ? 0 : y + 1, z != 7, w != 9 UNSAT. Assert always true

Slide 7

Slide 7 text

7 / 23 Verication example Program: int x; int y=8,z=0,w=0; if (x) z = y - 1; else w = y + 1; assert (z == 5 || w == 9) Constraints: y = 8, z = x ? y -1 : 0, w = x ? 0 : y + 1, z != 5, w != 9 SAT. Program contains a bug Counterexample: y = 8, x = 1, w = 0, z = 7

Slide 8

Slide 8 text

8 / 23 Borealis

Slide 9

Slide 9 text

9 / 23 Program representation

Slide 10

Slide 10 text

10 / 23 Problem void print_element(int* arr , int num){ printf("arr=%i\n", arr[num]); // Check } void print_next_element(int* arr , int num){ print_element(arr , num + 1); } int main(int argc , char* argv []) { int a[] = {1, 2, 3}; print_element(a, 0); print_next_element(a, 0); return 0; }

Slide 11

Slide 11 text

11 / 23 Solution Call graph traversal Extraction of information which aects variables from security properties Combining of extracted information

Slide 12

Slide 12 text

12 / 23 Call graph for program example void print_element(int* arr , int num){ printf("arr=%i\n", arr[num]); } void print_next_element(int* arr , int num){ print_element(arr , num + 1); } int main(int argc , char* argv []) { int a[] = {1, 2, 3}; print_element(a, 0); print_next_element(a, 0); return 0; }

Slide 13

Slide 13 text

13 / 23 Collect phase Given a function F and its safety property Q, we collecting argument-specic information, which is relevant to Q, from all call sites of F Slicing function w.r.t current query Dealing with recursion Handling of nested calls

Slide 14

Slide 14 text

14 / 23 Nested call inuence example int get_next_index(int a) { return a + 1; } void print_element(int* arr , int num) { printf("arr=%i\n", arr[num]); } void print_next_element(int* arr , int num) { int idx = get_next_index(num); print_element(arr , idx); } int main(int argc , char* argv []) { int a[] = {1, 2, 3}; print_element(a, 0); print_next_element(a, 0); return 0; }

Slide 15

Slide 15 text

15 / 23 Merging information void print_element(int* arr , int num){ printf("arr=%i\n", arr[num]); // Check } int main(int argc , char* argv []) { int a[] = {1, 2, 3}; print_element(a, 0); return 0; } Equality predicates at junctions arr = a; num = 0

Slide 16

Slide 16 text

16 / 23 Resulting PS for example int get_next_index(int a) { return a + 1; } void print_element(int* arr , int num) { printf("arr=%i\n", arr[num]); } void print_next_element(int* arr , int num) { int idx = get_next_index(num); print_element(arr , idx); } int main(int argc , char* argv []) { int a[] = {1, 2, 3}; print_element(a, 0); print_next_element(a, 0); return 0; } main_ %0= alloca (3,(3 * 1)), @I arraydecay1=gep[inbounds ](main_ %0 ,0+0+0), print_next_element_num =0 print_next_element_arr=arraydecay1 )->( @I next_index =( print_next_element_num + 1), print_next_element_call=next_index )->( num=print_next_element_call arr=print_next_element_arr )->( @I idxprom=cast(+ Integer (64), num), @I arrayidx=gep(arr ,0+ idxprom))

Slide 17

Slide 17 text

17 / 23 Combining phase PS corresponds to a formula of the form P0 ∨ P1 ∨ . . . ∨ Pn Pi - distinct calling context For PS we have to create synthetic variable free_var

Slide 18

Slide 18 text

18 / 23 Resulting PS example (BEGIN ( @P free_var =0 )->( main_ %0= alloca (3,(3 * 1)), @I main_arraydecay=gep[inbounds ]( main_ %0 ,0+0+0), num=0 arr=main_arraydecay )->( @I idxprom=cast(+ Integer (64), num), @I arrayidx=gep(arr ,0+ idxprom) ), ( @P free_var =1 )->( main_ %0= alloca (3,(3 * 1)), @I main_arraydecay1=gep[inbounds ]( main_ %0 ,0+0+0), print_next_element_num =0 print_next_element_arr=main_arraydecay1 )->( @I get_next_index_add =( print_next_element_num + 1), print_next_element_call=get_next_index_add )->( num=print_next_element_call arr=print_next_element_arr )->( @I idxprom=cast(+ Integer (64), num), @I arrayidx=gep(arr ,0+ idxprom) ) END)

Slide 19

Slide 19 text

19 / 23 Processing to solver There are 2 equivalent ways of processing it via an SMT solver As one large formula Each small disjunct separately

Slide 20

Slide 20 text

20 / 23 Testing We tested the prototype in the following congurations: Basic intraprocedural BMC (intra) BMC with full inlining (inline) Our interprocedural BMC approach (inter)

Slide 21

Slide 21 text

21 / 23 Testing

Slide 22

Slide 22 text

22 / 23 Conclusion Our main takeaways are as follows: Interprocedural analysis is a bottleneck for BMC The speed of the algorithm depends not so much on the size of the project as the complexity of its internal connections

Slide 23

Slide 23 text

23 / 23 Contact information {stepanov, akhin, belyaev}@kspt.icc.spbstu.ru Borealis repository: https://bitbucket.org/vorpal-research/borealis