Modular, compositional and sound verification of the input/output behavior of programs Willem Penninckx, Bart Jacobs, Frank Piessens Department of Computer Science, KU Leuven, Belgium DRADS 2014
Table of Contents Introduction Requirements Specifying I/O behaviour Wrapping up
Table of Contents Introduction Requirements Specifying I/O behaviour Wrapping up
Popular way to prove software properties ◮ Theorem: ◮ Possible proofs: ◮ When is a proof correct?
Popular way to prove software properties ◮ Theorem: Informal: returns a bigger number ◮ Possible proofs: ◮ When is a proof correct?
Popular way to prove software properties ◮ Theorem: Informal: returns a bigger number Formal: ◮ Possible proofs: ◮ When is a proof correct?
Popular way to prove software properties ◮ Theorem: Informal: returns a bigger number Formal: if x > y then result := x else result := y ◮ Possible proofs: ◮ When is a proof correct?
Popular way to prove software properties ◮ Theorem: Informal: returns a bigger number Formal: if x > y then result := x else result := y { result > = x ∧ result > = y } ◮ Possible proofs: ◮ When is a proof correct?
Popular way to prove software properties ◮ Theorem: Informal: returns a bigger number Formal: {} if x > y then result := x else result := y { result > = x ∧ result > = y } ◮ Possible proofs: ◮ When is a proof correct?
Popular way to prove software properties ◮ Theorem: Informal: returns a bigger number Formal: {} if x > y then result := x else result := y { result > = x ∧ result > = y } ◮ Possible proofs: No time to explain! ◮ When is a proof correct?
Popular way to prove software properties ◮ Theorem: Informal: returns a bigger number Formal: {} if x > y then result := x else result := y { result > = x ∧ result > = y } ◮ Possible proofs: No time to explain! ◮ When is a proof correct? No time to explain!
{ x = 2 } x := x + 1 { x = 3 } ◮ � �� � � �� � state before program starts state after program terminates ◮ People added support for... ◮ Concurrency ◮ Dynamic memory allocation ◮ ...
{ x = 2 } x := x + 1 { x = 3 } ◮ � �� � � �� � state before program starts state after program terminates ◮ People added support for... ◮ Concurrency ◮ Dynamic memory allocation ◮ ... ◮ Typically verified: (memory) state.
{ x = 2 } x := x + 1 { x = 3 } ◮ � �� � � �� � state before program starts state after program terminates ◮ People added support for... ◮ Concurrency ◮ Dynamic memory allocation ◮ ... ◮ Typically verified: (memory) state. ◮ End-users care about: what’s on their screen.
{ x = 2 } x := x + 1 { x = 3 } ◮ � �� � � �� � state before program starts state after program terminates ◮ People added support for... ◮ Concurrency ◮ Dynamic memory allocation ◮ ... ◮ Typically verified: (memory) state. ◮ End-users care about: what’s on their screen. ◮ = > Add support to verify Input/Output (I/O)
Table of Contents Introduction Requirements Specifying I/O behaviour Wrapping up
{...} main(){ code; code; code; code; code; code; code; code; ... code; } {...}
{...} {...} {...} {...} main(){ main(){ f1(){ f1(){ code; f1(); f3(); f3(); code; f2(); f4(); f4(); code; } } } code; {...} {...} {...} code; code; {...} {...} code; f2(){ f2(){ code; f4(); f4(); ... f5(); f5(); code; } } } {...} {...} {...}
{...} {...} {...} {...} main(){ main(){ f1(){ f1(){ code; f1(); f3(); f3(); code; f2(); f4(); f4(); code; } } } code; {...} {...} {...} code; code; {...} {...} code; f2(){ f2(){ code; Compositionality f4(); f4(); ... f5(); f5(); code; } } } {...} {...} {...}
{...} {...} {...} {...} main(){ main(){ f1(){ f1(){ code; f1(); f3(); f3(); code; f2(); f4(); f4(); code; } } } code; {...} {...} {...} code; code; di ff erent {...} {...} developers code; f2(){ f2(){ code; f4(); f4(); ... f5(); f5(); Modularity code; } } } {...} {...} {...}
{specs specs specs specs} main(){ ... } { specs specs specs specs}
{specs specs spec1= specs spec3 { spec1 specs} * spec4 * spec2} main(){ main(){ ... ... } } { specs spec2= specs spec4 specs * spec5 specs} .
{specs specs spec1= specs spec3 { spec1 specs} * spec4 * spec2} main(){ main(){ ... ... } } { specs spec2= specs Compositionality spec4 specs * spec5 specs} .
{specs specs spec1= specs spec3 { spec1 specs} * spec4 * spec2} main(){ main(){ ... ... } } { di ff erent developers specs spec2= specs spec4 specs * spec5 Modularity specs} .
Requirements ◮ Compositionality. ◮ e.g. define I/O action download on top of tcp write and file write , etc.
Requirements ◮ Compositionality. ◮ e.g. define I/O action download on top of tcp write and file write , etc. ◮ Modularity ◮ e.g. combine independent I/O action tcp write with file write
Requirements ◮ Compositionality. ◮ e.g. define I/O action download on top of tcp write and file write , etc. ◮ Modularity ◮ e.g. combine independent I/O action tcp write with file write ◮ Non-terminating programs (part WIP) ◮ e.g. {} while true ... { these I/O happened } : postcondition useless
Requirements ◮ Compositionality. ◮ e.g. define I/O action download on top of tcp write and file write , etc. ◮ Modularity ◮ e.g. combine independent I/O action tcp write with file write ◮ Non-terminating programs (part WIP) ◮ e.g. {} while true ... { these I/O happened } : postcondition useless ◮ Actions depend on outcome of actions ◮ e.g. read file containing filenames to read ◮ ...
Table of Contents Introduction Requirements Specifying I/O behaviour Wrapping up
By example
By example ◮ {} ... {} ◮ No I/O allowed
By example ◮ {} ... {} ◮ No I/O allowed ◮ { time ( t 1 ) } ... { time ( t 1 ) } ◮ No I/O allowed ◮ A time like t 1 ≈ a point in time. ◮ Doing I/O “increases” time
By example ◮ {} ... {} ◮ No I/O allowed ◮ { time ( t 1 ) } ... { time ( t 1 ) } ◮ No I/O allowed ◮ A time like t 1 ≈ a point in time. ◮ Doing I/O “increases” time ◮ { time ( t 1 ) ⋆ print io( t 1 , ‘h ′ , t 2 ) } print char(‘h ′ ); { time ( t 2 ) } ◮ Doing print char(‘h’) ◮ requires a permission print io( t 1 , ‘h ′ , t 2 ) ◮ requires a time ( t 1 ) ◮ disposes the permission ◮ “increases” the time to t 2
◮ { time ( t 1 ) ⋆ print io( t 1 , ‘h ′ , t 2 ) ⋆ print io( t 2 , ‘i ′ , t 3 ) } ... { time ( t 3 ) } ◮ Can print “hi”, “h”, “”. ◮ If terminates: can only print “hi”. ◮ Can not print: “x”, “i”, “ih”, ...
◮ { time ( t 1 ) ⋆ print io( t 1 , ‘h ′ , t 2 ) ⋆ print io( t 2 , ‘i ′ , t 3 ) } ... { time ( t 3 ) } ◮ Can print “hi”, “h”, “”. ◮ If terminates: can only print “hi”. ◮ Can not print: “x”, “i”, “ih”, ... ◮ { time ( t 1 ) ⋆ print io( t 1 , ‘h ′ , t 2 ) ⋆ print io( t 1 , ‘i ′ , t 2 ) } ... { time ( t 2 ) } ◮ Can print “h”, “i”, “”. ◮ If terminates: has printed either “h” or “i”. ◮ Can not print: “x”, “hi”, ...
Defining new I/O actions ◮ predicate print string io( t 1 , str , t 2 ) = if str = nil then t 1 = t 2 else ( print io( t 1 , head( str ) , t between ) ⋆ print string io( t between , tail( str ) , t 2 ) )
Defining new I/O actions ◮ predicate print string io( t 1 , str , t 2 ) = if str = nil then t 1 = t 2 else ( print io( t 1 , head( str ) , t between ) ⋆ print string io( t between , tail( str ) , t 2 ) ) ◮ Build actions using actions (compositionality)
Defining new I/O actions ◮ predicate print string io( t 1 , str , t 2 ) = if str = nil then t 1 = t 2 else ( print io( t 1 , head( str ) , t between ) ⋆ print string io( t between , tail( str ) , t 2 ) ) ◮ Build actions using actions (compositionality) ◮ { time ( t 1 ) ⋆ print string io( t 1 , “hello world! ′′ , t 2 ) } ... { time ( t 2 ) }
Linking arguments ◮ { time ( t 1 ) ⋆ read string io( t 1 , str , t 2 ) ⋆ print string io( t 2 , str , t 3 ) } ... { time ( t 3 ) }
Unconstrained order/interleaving ◮ { time ( t 2 ) ⋆ time ( t 3 ) ⋆ read string io( t 2 , str , t 4 ) ⋆ print string io( t 3 , str , t 5 ) } ... { time ( t 4 ) ⋆ time ( t 5 ) } ◮ Allows buffering of any size.
Unconstrained order/interleaving ◮ { time ( t 2 ) ⋆ time ( t 3 ) ⋆ read string io( t 2 , str , t 4 ) ⋆ print string io( t 3 , str , t 5 ) } ... { time ( t 4 ) ⋆ time ( t 5 ) } ◮ Allows buffering of any size. ◮ How to get two times ( time ( t 2 ) and time ( t 3 ))?
Unconstrained order/interleaving ◮ { time ( t 1 ) ⋆ split ( t 1 , t 2 , t 3 ) ⋆ read string io( t 2 , str , t 4 ) ⋆ print string io( t 3 , str , t 5 ) ⋆ join ( t 4 , t 5 , t 6 ) } ... { time ( t 4 ) } ◮ split ( t 1 , t 2 , t 3 ) consumes time ( t 1 ) and yields time ( t 2 ) and time ( t 3 ).
Table of Contents Introduction Requirements Specifying I/O behaviour Wrapping up
Recommend
More recommend