Constructor Institute of Technology Reif — Research Eiffel

Debugging verification

The only feedback given by AutoProof is whether a routine is successfully verified or if some specific assertions could not be proven. When the verification fails it can be necessary to find out which facts the verifier could establish or even guide the verifier to the right conclusion. For this you can use intermediate assertions (check instructions in Eiffel). During the debug- ging process it can also be beneficial to assume specific facts and thus limit the possible executions that the verifier considers during the proof.

Assertions

Using Eiffel’s check instruction you can add an intermediate assertion that will be verified by AutoProof. This can help to check if you have the same understanding of the state at a program point as the verifier. You can add multiple expressions to a single check instruction, and each expression can be equipped with a tag. AutoProof will show the tags in error messages.

check tag: expr end

Check instruction to establish if expr holds.

Note that it is possible that when you have multiple consecutive assertions successfully verified, removing an intermediate assertion will make the verification of later assertions fail. In these cases you have to keep the assertion in order to guide the verifier towards the successful verification.

Assumptions

Eiffel does not support assumptions out of the box. To write an assumption in AutoProof, you have to write a check instruction with the special tag assume. AutoProof will assume the expression for the rest of the routine without checking it.

You can use assumptions to limit the executions considered by the verifier. For example by assuming False in a branch of a conditional instruction the verification of that branch will always succeed.

if ... then
	...
else
	check assume: False end
end

Ignores all code path that go through the else branch.

Another way to use assumptions to limit executions it by restricting the state space of otherwise unrestricted values. This can be used for example to ignore executions where an array is empty.

check assume: not a.is_empty end

Ignores executions where a is empty.

Inconsistencies

It can happen that verification succeeds due to inconsistent contracts or assumptions. If you for example have a routine with the precondition a > 0 and an additional class invariant a < 0 (or an assumption a < 0 in the body of the routine), your specification is inconsistent. This is essentially equivalent to an assumption of False and the verifier will be able to derive any fact from it, including false ones.

A quick (though not completely safe) check for inconsistencies is to add an assertion or postcondition False to your routine. If the verifier manages to prove the assertion, this is a sign for an inconsistency in the specification.