Regression Verification for unbalanced recursive functions OFER STRICHMAN
Regression Verification for unbalanced recursive functions OFER STRICHMAN MAO R VEIT SMAN TECHN ION, HAIFA, ISRAEL 1
Regression Verification Develop a method formally verifying the equivalence of two similar programs. Selling points: ◦ Specification: not needed ◦ Complexity: depends on the semantic difference between the programs, and not on their size. 2
Partial Equivalence § There are many definitions of equivalence. § We will focus on partial equivalence: § Executions of P 1 and P 2 on equal inputs ◦ …which terminate, ◦ result in equal outputs. § Undecidable 3
Partial Equivalence for Recursive Functions Consider the call graphs: A B Side 1 Side 2 ◦ … where A, B have: ◦ same prototype ◦ no loops Prove partial equivalence of A, B ◦ How shall we handle the recursion ? 4
Hoare’s Rule for Recursion Let A be a recursive function. 5
Hoare’s Rule for Recursion // {p} A(. . . ) { . . . // {p} call A(. . . ); // {q} . . . } // {q} 6
Proving Partial Equivalence //in[A] A(. . . ) { . . . //in[call A] call A(. . . ); //out[call A] . . . } //out[A] 7 A //in[B] B(. . . ) { . . . // in[call B] call B(. . . ); //out[call B] . . . } //out[B] B
Proving Partial Equivalence Q: How can a verification condition for the premise look like? A: Replace the recursive calls with calls to functions that ◦ over-approximate A, B, and ◦ are partially equivalent by construction Natural candidates: Uninterpreted Functions 8
Proving Partial Equivalence Let AUF , BUF be A, B, after replacing the recursive call with a call to (the same) uninterpreted function. We can now rewrite the rule: The premise is decidable 9
Incompleteness of PART-EQ We will tackle two causes of incompleteness: 1. Non-equivalent base cases. 2. Unbalanced recursive steps (functions not in lock-step). . . and show a broad approach to improve completeness of PART-EQ 10
What (PART-EQ) cannot prove (1) Calling under different base conditions: int fact 1(int n){ int fact 2(int n){ if (n <= 1) return 1; if (n <= 0) return 1; return n * fact 1(n-1); return n * fact 2(n-1); fact_uf(n-1); } } 11
The verification condition int main(){ int n = non_det(); // suppose n = 1 int ret 1, ret 2; ret 1 = fact 1(n); // returns 1 ret 2 = fact 2(n); // returns nondet assert(ret 1 = ret 2); // fails ! } • We check this program with a bounded model checker (i. e. CBMC). 12
What (PART-EQ) cannot prove (2) Unbalanced recursive functions lead to function calls with different arguments: int sum 1(int n){ if (n <= 1){ return n; } return n + n-1 +sum 1(n-2); } returns n + n -1 + nondet() int sum 2(int n){ if (n <= 1){ return n; } return n + sum 2(n-1); } returns n + nondet() 13
Our strategy 14
New Proof Rule 15
16
int fact 1_1(int n){ assume(FALSE); } int fact 1(int n){ if (n <= 1) return 1; return n * fact 1_1(n-1); } 18
20
Non Balanced Recursive Step - Solution int sum 1(int n){ if (n <= 1){ return n; } return n + n-1 + sum 1(n-2); uf_sum(n-2); } 8 + 7 + uf_sum(6) int sum 2_1(int n){ if (n <= 1){ return n; } uf_sum(n-1); return n + sum 2_1(n-1); } 7 + uf_sum(6) int sum 2(int n){ if (n <= 1){ return n; } return n + sum 2_1(n-1); } 8 23
Non Balanced Recursive Step - Problem int sum 1(int n){ if (n <= 1){ return n; } uf_sum(n-2); return n + n-1 +sum 1(n-2); } int sum 2_1(int n){ if (n <= 1){ return n; } uf_sum(n-1); return n + sum 2_1(n-1); } int sum 2(int n){ if (n <= 1){ return n; } return n + sum 2_1(n-1); } 24
Can software verifiers prove equivalence? 25
Value analysis int foo(int n){ if (n <= 1){ return n; } return n + n-1; } 26
Using value analysis when proving equivalence 27
Questions? 28
- Slides: 24