Open guancio opened 5 years ago
For the tutorial we used a simple approach. We take an additional list of labels, for which we use false
as precondition. This approach is sound because {false}l->ls{Q}
always holds. If we want different precondition per exit-point we can now compute
P1=WP(l1, {l2}, {l3}, I and c)
, which uses the initial triple {false}l3->{l2}{I and c}
and generates the contract {P1}l1->{l2}{I and c}
, andP2=WP(l1, {l3}, {l2}, I and not c)
, which uses the initial triple {false}l2->{l3}{I and not c}
and generates the contract {P2}l1->{l3}{I and not c}
A benefit of this approach is that it can also be used to speed up analysis of dead code, since it simply propagates false along paths that we do not want to analyse.
We could generalize this approach, by allowing the WP
procedure to take a list of initial contracts: WP(l, ls, thms, Q)
, where each theorem in thms
is a contract {P}l1->ls{Q}
.
An alternative approach is to change the definition of the triple, allowing to specify different postcondition for different exit points. E.g {P}l1[l2->Q, l3->Q', etc]
.
This approach could make sense for the general Hoare triple, but it does not simplifiy the work for the wp algorithm. In fact, except very few exceptions this approach will force us to repeat the work for each postcondition. In this case it is easier to just generate several contracts, with the other approach.
In fact, except very few exceptions this approach will force us to repeat the work for each postcondition.
Can you elaborate on this point? I don't see why this wouldn't work or would complicate the WP propagation procedure.
For {P} l1 -> {l2, l3, etc} [l2 |-> Q, l3 |-> Q', etc]
I also see advantages when producing HT for functions having early returns for error handling (for example), where you don't want to impose too strong postconditions in those exit points.
A benefit of this approach is that it can also be used to speed up analysis of dead code, since it simply propagates false along paths that we do not want to analyse.
Yes, it could do this, however the current version doesn't actually do this. Right now everything after (in order of concrete execution) the False-triple block is generated as usual, then just thrown away by the analysis. If we want to continue with this approach we mustn't forget to implement the time-saving tricks that are made possible by introducing the False-triple.
The original tool weakest precondition had the signature
WP(l,ls,Q)
, wherel
is the initial label,ls
are the labels of the exit points, andQ
is the postcondition. This generates the weakest preconditonP
that guarantees the program reaches an exit point and thatQ
is establishes as soon a label inls
is reached.This approach forces us to establish the same postconditions for all exit points, which can be undesirable. For example
If this fragment implements the guard of a while loop,
l2
is the entry point of the loop body, andl3
is the first label outside the loop, we would like to verify{I and c} l1 -> {l2} {I and c}
and{I and not c} l1 -> {l3} {I and not c}
. This is not possible using the the original procedure for weakest precondition.ls={l2,l3}
thenQ
must be the same for both exit pointsWP(l1,{l2},I and c)
, then the algorithm cannot compute the WP ofl1
since it does not know the postcondition of on of the target addresses (i.e. l3).WP(l1,{l2,l3},I and c and (pc \neq l3)
. However, BIR does not allow postconditions to reason about the program counter.