A Verification Condition Visualizer Andrew Ireland and Madiha Jami School of Mathematical & Computer Sciences Heriot-Watt University Edinburgh Nov-18 CIAO 2014 - DFKI Bremen
Motivations Nov-18 CIAO 2014 - DFKI Bremen
Overview If pictures help develop intuitions about data structures, why not exploit them more? Engage students and broaden the accessibility of formal verification technologies Productivity gains within industrial scale formal verification, i.e. Help decide if a proof effort is worth while or not If yes then provides guidance as to how the proof might proceed If no then provides guidance as to where bugs and inconsistences lie Focus on arrays and a prototype tool (MSc Project) Outline work in progress and future vision Funded by EPSRC Platform Grant EP/J001058 Nov-18 CIAO 2014 - DFKI Bremen
Basic Building Blocks Element: Segment: .… Concrete Arbitrary Index i Property P .… i P Nov-18 CIAO 2014 - DFKI Bremen
Properties & Relations … … … P … … ... … R 28/11/2018 CIAO 2014 - DFKI Bremen
Updates i A(i):= E A(i):= A(j) t:= A(i); A(i):=A(j); A(j):= t E i j .… …. .… i j .… …. .… update(update(A, [i], element(A, [j])), [j], element(A, [i])) Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag --# pre (for all I in IndexRange => (Flag(I)=Red or Flag(I)=White)) --# post for some P in Integer range (Flag'First) .. (Flag'Last+1) => --# ((for all Q in Integer range Flag'First..(P-1) => (Flag(Q)=Red)) and --# (for all R in Integer range P..Flag'Last => (Flag(R)=White))); Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag …. .… …. red white f l red or white f P-1 P l Nov-18 .… …. red white Nov-18 CIAO 2014 - DFKI Bremen
SPARK Code loop … if else J:=J-1; T:=Flag(I); Flag(I):=Flag(J); Flag(J):=T; end if; end loop; SPARK Code procedure Partition_Section(Flag: in out ArrayOfColours) is subtype JustBiggerRange is Integer range Flag'First .. Flag'Last+1; I: JustBiggerRange; J: JustBiggerRange; T: Colour; begin I:=Flag'First; J:=Flag'Last+1; loop --# assert Flag'First<=I and --# J<=(Flag'Last+1) and --# I<=J and --# (for all Q in Integer range Flag'First..(I-1) => (Flag(Q)=Red)) and --# (for all R in Integer range J..Flag'Last => (Flag(R)=White)); exit when I=J; if Flag(I)=Red then I:=I+1; else J:=J-1;T:=Flag(I); Flag(I):=Flag(J); Flag(J):=T; end if; end loop; end Partition_Section Nov-18 CIAO 2014 - DFKI Bremen
procedure_partition_section_5. H1: indexrange__first <= i . H2: j <= indexrange__last + 1 . H3: i <= j . H4: for_all (q_: integer, ((q_ >= indexrange__first) and ( q_ <= i - 1)) -> (element(flag, [q_]) = red)) . H5: for_all (r_: integer, ((r_ >= j) and (r_ <= indexrange__last)) -> (element(flag, [r_]) = white)) . H6: for_all (i___1: integer, ((i___1 >= indexrange__first) and ( i___1 <= indexrange__last)) -> ((element(flag, [ i___1]) >= colour__first) and (element(flag, [ i___1]) <= colour__last))) . H7: for_all (i_: integer, ((i_ >= indexrange__first) and ( i_ <= indexrange__last)) -> ((element(flag~, [i_]) = red) or (element(flag~, [i_]) = white))) . H8: not (i = j) . H9: j >= pointerrange__first . H10: j <= pointerrange__last . H11: i >= pointerrange__first . H12: i <= pointerrange__last . H13: i >= indexrange__first . H14: i <= indexrange__last . H15: not (element(flag, [i]) = red) . H16: j - 1 >= justbiggerrange__first . H17: j - 1 <= justbiggerrange__last . H18: element(flag, [i]) >= colour__first . H19: element(flag, [i]) <= colour__last . H20: i >= indexrange__first . H21: i <= indexrange__last . H22: element(flag, [j - 1]) >= colour__first . H23: element(flag, [j - 1]) <= colour__last . H24: j - 1 >= indexrange__first . H25: j - 1 <= indexrange__last . H26: i >= indexrange__first . H27: i <= indexrange__last . H28: element(flag, [i]) >= colour__first . H29: element(flag, [i]) <= colour__last . H30: j - 1 >= indexrange__first . H31: j - 1 <= indexrange__last . -> C1: indexrange__first <= i . C2: j - 1 <= indexrange__last + 1 . C3: i <= j - 1 . C4: for_all (q_: integer, ((q_ >= indexrange__first) and ( q_ <= i - 1)) -> (element(update(update(flag, [i], element( flag, [j - 1])), [j - 1], element(flag, [i])), [ q_]) = red)) . C5: for_all (r_: integer, ((r_ >= j - 1) and (r_ <= indexrange__last)) -> (element(update(update( flag, [i], element(flag, [j - 1])), [j - 1], element( flag, [i])), [r_]) = white)) . C6: for_all (i___1: integer, ((i___1 >= indexrange__first) and ( i___1 <= indexrange__last)) -> ((element(update(update( flag, [i])), [i___1]) >= colour__first) and (element(update(update( flag, [i])), [i___1]) <= colour__last))) . C7: for_all (i_: integer, ((i_ >= indexrange__first) and ( Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ loop-else ] procedure_partition_section_5 . ... H3: i <= j . H4: for_all(q_: integer, ((q_ >= indexrange__first) and (q_ <= i - 1)) -> (element(flag, [q_]) = red)) . H5: for_all(r_: integer, ((r_ >= j) and (r_ <= indexrange__last)) -> (element(flag, [r_]) = white)) . H12: not (i = j) . H17: not (element(flag, [i]) = red) . … -> C4: for_all(q_: integer, ((q_ >= indexrange__first) and (q_ <= i - 1)) -> (element(update(update(flag, [i], element(flag, [j - 1])), [j - 1], element(flag, [i])), [ q_]) = red)) . C5: for_all(r_: integer, ((r_ >= j - 1) and (r_ <= indexrange__last)) -> (element(update(update( flag, [i], element(flag, [j - 1])), [j - 1], element(flag, [i])), [r_]) = white)) . Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ loop-else ] j l .… …. .… Given: red white white f i j-1 l .… …. .… Goal: red white Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ post-loop ] procedure_partition_section_14. H1: indexrange__first <= i . H2: j <= indexrange__last + 1 . … H4: for_all (q_: integer, ((q_ >= indexrange__first) and (q_ <= i - 1)) -> (element(flag, [q_]) = red)) . H5: for_all (r_: integer, ((r_ >= j) and (r_ <= indexrange__last)) -> (element(flag, [r_]) = white)) . H8: i = j . -> C1: for_some (p_: integer, ((p_ >= indexrange__first) and ( p_ <= indexrange__last + 1)) and (( for_all (q_: integer, ((q_ >= indexrange__first) and (q_ <= p_ - 1)) -> (element( flag, [q_]) = red))) and ( for_all (r_: integer, (( r_ >= p_) and (r_ <= indexrange__last)) -> (element( flag, [r_]) = white))))) . Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ post-loop ] j l .… …. Given: red white f P-1 P l Goal: .… …. red white Nov-18 CIAO 2014 - DFKI Bremen
Revised SPARK Code procedure Partition_Section(Flag: in out ArrayOfColours) is subtype JustBiggerRange is Integer range Flag'First .. Flag'Last+1; I: JustBiggerRange; J: JustBiggerRange; T: Colour; begin I:=Flag'First; J:=Flag'Last+1; loop --# assert Flag'First<=I and --# J<=(Flag'Last+1) and --# I<=J and --# (for all Q in Integer range Flag'First..(I+1) => (Flag(Q)=Red)) and --# (for all R in Integer range J..Flag'Last => (Flag(R)=White)); exit when I=J; if Flag(I)=White then J:=J-1;T:=Flag(I); Flag(I):=Flag(J); Flag(J):=T; I:=I+1; else end if; end loop; end Partition_Section Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ loop-then ] Revisited procedure_partition_section_4. … H3: i <= j . H4: for_all(q_: integer, ((q_ >= indexrange__first) and ( q_ <= i + 1)) -> (element(flag, [q_]) = red)) . H12: not (i = j) . H17: element(flag, [i]) = white . -> C4: for_all(q_: integer, ((q_ >= indexrange__first) and ( q_ <= i + 1)) -> (element(update(update(flag, [i], element( flag, [j - 1])), [j - 1], element(flag, [i])), [q_]) = red)) . ? Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ loop-then ] Revisited j l .… …. .… Given: red white white contradiction f i i+1 j-1 j l .… …. . … Goal: red white Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ loop-else ] Revisited procedure_partition_section_5. … H3: i <= j . H4: for_all(q_: integer, ((q_ >= indexrange__first) and ( q_ <= i + 1)) -> (element(flag, [q_]) = red)) . H12: not (i = j) . H17: not (element(flag, [i]) = white) . -> C4: for_all(q_: integer, ((q_ >= indexrange__first) and ( q_ <= i + 1 + 1)) -> (element(flag, [q_]) = red)) . ? Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ loop-else ] Revisited j l .… …. .… Given: red white red f i i+1 i+2 j l Goal: .… …. .… red white unprovable Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ post-loop ] Revisited procedure_partition_section_12. … H3: i <= j . H4: for_all(q_: integer, ((q_ >= indexrange__first) and (q_ <= i + 1)) -> (element(flag, [q_]) = red)) . H5: for_all(r_: integer, ((r_ >= j) and (r_ <= indexrange__last)) -> (element(flag, [r_]) = white)) . H12: i = j . -> C1: for_some(p_: integer, ((p_ >= indexrange__first) and ( p_ <= indexrange__last + 1)) and ((for_all(q_: integer, ((q_ >= indexrange__first) and (q_ <= p_ - 1)) -> (element( flag, [q_]) = red))) and (for_all(r_: integer, (( r_ >= p_) and (r_ <= indexrange__last)) -> (element( flag, [r_]) = white))))) . ? Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ post-loop ] Revisited j i+1 l .… …. Given: white red contradiction f P-1 P l Goal: .… …. red white Nov-18 CIAO 2014 - DFKI Bremen
Core Algorithm Identification of the arrays that are explicitly referenced within the given hypotheses and conclusions Extraction of properties and relations of the elements and segments that are contained within the identified arrays, including constraints on index variables and upper and lower bounds Ordering the elements and segments that are explicitly identified above, this may involve elementary reasoning with regards to the constraints extracted for index variables Positioning the elements and segments, i.e. determining if segments (and elements) are adjoining non-adjoining overlapping Note: Implicit gaps and overlaps are calculated, i.e. either a fixed number of consecutive elements or an arbitrary segment Nov-18 CIAO 2014 - DFKI Bremen
Auto-VCV Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ loop-else ] Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ loop-then ] Revisited Nov-18 CIAO 2014 - DFKI Bremen
Bubble Max subtype Index_Type is Integer range 1 .. 9; type Array_Type is array (Index_Type) of Integer; ... procedure Bubble_Max(Table: in out Array_Type) is R: Index_Type; T: Integer; begin R:= 1; loop --# assert (for all I in Integer range Table'First .. (R-1) => (Table(I) <= Table(R))); exit when R = Index_Type'Last; R:=R+1; if Table(R-1) > Table(R) then T:= Table(R); Table(R):= Table(R-1); Table(R-1):= T; end if; end loop; end Bubble_Max; Nov-18 CIAO 2014 - DFKI Bremen
Bubble Max [ true branch ] procedure_bubble_max_3. H1: for_all(i_: integer, ((i_ >= index_type__first) and (i_ <= r - 1)) -> (element(table, [i_]) <= element(table, [r]))) . ... H18: element(table, [r + 1 - 1]) > element(table, [r + 1]) . -> C1: for_all(i_: integer, ((i_ >= index_type__first) and (i_ <= r + 1 - 1)) -> (element(update(update( table, [r + 1], element(table, [r + 1 - 1])), [r + 1 - 1], element( table, [r + 1])), [i_]) <= element(update(update(table, [r + 1], element(table, [r + 1 - 1])), [r + 1 - 1], element(table, [r + 1])), [r + 1]))) . Nov-18 CIAO 2014 - DFKI Bremen
Bubble Max [ true branch ] Nov-18 CIAO 2014 - DFKI Bremen
Future Work Relations between pictures, e.g. output is a permutation of the input Deal with user definitions, i.e. proof functions Array of arrays, arrays of records, records of … Represent buggy cases as concrete pictures Industrial scale examples, e.g. 90+ hypotheses, arrays of records with arrays, … Working with BAE Systems (Warton, UK) – advanced avionics control systems written in SPARK – productivity gain “would reduce time spent deciding if a VC is provable” Nov-18 CIAO 2014 - DFKI Bremen
Future Work Possibly target Boogie – the generic VCG would enable the ideas to be applied to many more programming languages Pointer based programs - separation logic provides a natural formalism for extracting pictures From verification to synthesis – interactively evolve formal invariants via a programmer’s data structure sketches? Proof by pictures? Nov-18 CIAO 2014 - DFKI Bremen
Conclusion Pictures help in developing programming and proof intuitions about data structures Verification tools that include pictorial representations could, where appropriate, help: engage the next generation of software verification researchers broaden the accessibility and productivity of software verification technologies “A picture is worth a thousand words” “A formula is worth a thousand pictures” The truth lies somewhere between the two Nov-18 CIAO 2014 - DFKI Bremen
Extra Stuff … Nov-18 CIAO 2014 - DFKI Bremen
SPARK Code loop … if Flag(I)=Red then I:=I+1; else end if; end loop; procedure Partition_Section(Flag: in out ArrayOfColours) is subtype JustBiggerRange is Integer range Flag'First .. Flag'Last+1; I: JustBiggerRange; J: JustBiggerRange; T: Colour; begin I:=Flag'First; J:=Flag'Last+1; loop --# assert Flag'First<=I and --# J<=(Flag'Last+1) and --# I<=J and --# (for all Q in Integer range Flag'First..(I-1) => (Flag(Q)=Red)) and --# (for all R in Integer range J..Flag'Last => (Flag(R)=White)); exit when I=J; if Flag(I)=Red then I:=I+1; else J:=J-1;T:=Flag(I); Flag(I):=Flag(J); Flag(J):=T; end if; end loop; end Partition_Section Nov-18 CIAO 2014 - DFKI Bremen
For path(s) from assertion of line 94 to assertion of line 94: procedure_partition_section_4. H1: indexrange__first <= i . H2: j <= indexrange__last + 1 . H3: i <= j . H4: for_all (q_: integer, ((q_ >= indexrange__first) and ( q_ <= i - 1)) -> (element(flag, [q_]) = red)) . H5: for_all (r_: integer, ((r_ >= j) and (r_ <= indexrange__last)) -> (element(flag, [r_]) = white)) . H6: for_all (i___1: integer, ((i___1 >= indexrange__first) and ( i___1 <= indexrange__last)) -> ((element(flag, [ i___1]) >= colour__first) and (element(flag, [ i___1]) <= colour__last))) . H7: for_all (i_: integer, ((i_ >= indexrange__first) and ( i_ <= indexrange__last)) -> ((element(flag~, [i_]) = red) or (element(flag~, [i_]) = white))) . H8: not (i = j) . H9: j >= pointerrange__first . H10: j <= pointerrange__last . H11: i >= pointerrange__first . H12: i <= pointerrange__last . H13: i >= indexrange__first . H14: i <= indexrange__last . H15: element(flag, [i]) = red . H16: i + 1 >= justbiggerrange__first . H17: i + 1 <= justbiggerrange__last . -> C1: indexrange__first <= i + 1 . C2: j <= indexrange__last + 1 . C3: i + 1 <= j . C4: for_all (q_: integer, ((q_ >= indexrange__first) and ( q_ <= i + 1 - 1)) -> (element(flag, [q_]) = red)) . C5: for_all (r_: integer, ((r_ >= j) and (r_ <= indexrange__last)) -> (element(flag, [r_]) = white)) . C6: for_all (i___1: integer, ((i___1 >= indexrange__first) and ( i___1]) >= colour__first) and (element(flag, [i___1]) <= colour__last))) . C7: for_all (i_: integer, ((i_ >= indexrange__first) and ( i_ <= indexrange__last)) -> ((element(flag~, [i_]) = red) or (element(flag~, [i_]) = white))) . Nov-18 CIAO 2014 - DFKI Bremen
Polish Flag [ loop-then ] j l .… …. .… Given: red red white f i j l .… …. .… Goal: red white Nov-18 CIAO 2014 - DFKI Bremen