a scala compiler plugin for verification
play

a Scala Compiler Plugin for Verification Nada Amin Features - PowerPoint PPT Presentation

a Scala Compiler Plugin for Verification Nada Amin Features transform Scala def AST into a CFG front-end to lab verifier front-end to Eldarica support for design by contract partial understanding verified classes


  1. a Scala Compiler Plugin for Verification Nada Amin

  2. Features • transform Scala def AST into a CFG • front-end to lab verifier • front-end to Eldarica • support for • design by contract • partial understanding • verified classes

  3. Parity with Lab Verifier @verify def counter(length: Int) { assume(length > 0) var i: Int = 0 • @verify var j: Int = 1 assert(j <= length) while(j < length) { • assume / assert i = j - 1 assert(j < length) • loop invariants while(i >= 0) { i = i - 1 } j = j + 1 } assert(j == length) }

  4. Design by Contract @verify def even(n: Int): Int = { • precondition precondition(n >= 0) var r = 0 if (n == 0) r = 1 • assume when verifying else if (n == 1) r = 0 else r = odd(n-1) postcondition(r == 0 || r == 1) • assert when calling r } • postcondition @verify def odd(n: Int): Int = { precondition(n >= 0) • assert when verifying var r = 0 if (n == 0) r = 0 else if (n == 1) r = 1 • assume when calling else r = even(n-1) postcondition(r == 0 || r == 1) r }

  5. Design by Contract @verify def even(n: Int): Int = { precondition(n >= 0) var r = 0 if (n == 0) r = 1 else if (n == 1) r = 0 else r = odd(n-1) postcondition(r == 0 || r == 1) r }

  6. Simulating Havoc object ok { val random = new scala.util.Random() def havoc = random.nextInt - random.nextInt @verify def partition(b: Int) = { precondition(b >= 0) var P1:Int = 0 var P2:Int = 0 var a: Int = b var h: Int = 0 while(a > 0) { h = havoc if(h >= 0) P1 = P1 + 1 else P2 = P2 + 1 a = a - 1 } assert(P1 + P2 == b) val result = P1 postcondition(result <= b) result } }

  7. Partial Understanding @verify def test(queue: Queue) { var l = 0 var oldi = 0 var newi = 0 var q = queue do { l = lock (l) oldi = newi if (q.next != None) { q = q.next.get q.data = newi l = unlock (l) newi += 1 } } while (newi != oldi) l = unlock (l) } ((l == 0 && newi != oldi) || (l == 1 && newi == oldi))

  8. Partial Understanding class Queue(var data: Int, var next: Option[Queue]) @verify def lock(l: Int) = { precondition(l == 0) val r = 1 postcondition(r == 1) r } @verify def unlock(l: Int) = { precondition(l == 1) val r = 0 postcondition(r == 0) r }

  9. Verified Classes @verify class BankAccount { var balance = 0 @verify def withdraw(amount: Int) { precondition(amount >= 0 && balance >= amount) val old_balance = old(balance) balance -= amount postcondition( balance == old_balance - amount && balance >= 0) } @verify def deposit(amount: Int) { precondition(amount >= 0 && balance >= 0) val old_balance = old(balance) balance += amount postcondition(balance == old_balance + amount && balance >= 0) } }

  10. Verified Classes @verify class DoubleBankAccount { val savings = new BankAccount val checking = new BankAccount @verify def transfer(amount: Int) { precondition(amount >= 0 && savings.balance >= amount && checking.balance >= 0) val old_savings_balance = old(savings.balance) val old_checking_balance = old(checking.balance) savings.withdraw(amount) checking.deposit(amount) postcondition(savings.balance + checking.balance == old_savings_balance + old_checking_balance && savings.balance >= 0 && checking.balance >= 0) } }

  11. Eldarica • Predicate abstraction and interpolation • If it terminates: • Either successfully verifies CFG deriving loop invariants • Or finds a counterexample • Used mostly as a black-box • I extended it to show step-by-step trace for counterexample

  12. Eldarica Model for counterexample: == step 1 == @verify length ← 2 def test(length: Int) { == step 2 == assume(length > 0) i ← 0 var i: Int = 0 == step 3 == var j: Int = 1 j ← 1 while(j < length) { == step 4 == i = j - 1 i ← -1 while(i >= 0) { == step 5 == i = i - 1 j ← 3 } == final values == j = j + 2 // should be 1 i ← -1 } j ← 3 assert(j == length) } length ← 2 The program has a bug in asserting: (j == length)

  13. Limitations • false negatives due to partial understanding • false positives due to aliasing of verified classes • aliasing can also cause false negatives • severe limitations for verified classes • no support for recursive ADTs • underlying limitations of theorem prover

  14. False Negative def alwaysTrue() = true Model for counterexample: @verify def test() = { == step 1 == var x = 0 x ← 0 if (alwaysTrue()) { == step 2 == x += 1 x ← -1 } == final values == if (alwaysTrue()) { x ← -1 x -= 1 } The program has a bug in asserting: (x == 0) postcondition(x == 0) x }

  15. False Positive @verify class BankAccount { var balance = 0 @verify def withdraw(amount: Int, other: BankAccount ) { precondition(amount >= 0 && balance >= amount) val old_balance = old(balance) balance -= amount other.balance = 0 // other could be this! postcondition(balance == old_balance - amount && balance >= 0) } } warning: ignoring any aliasing involving other successfully verified withdraw with 1 warning(s)

  16. Conclusion • In retrospect, it seems like a bad idea to introduce features that lead to soundness holes. The trade-off might be acceptable: the holes are well-delimited. • Leon takes a different approach: soundly verify a functional subset of Scala.

  17. Questions?

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend