The following program demonstrates the bug.
predicate P(x: Perm)
{
x == none ==> false
}
method foo()
{
inhale P(write)
unfold P(perm(P(write)))
assert false // successfully verified
}
Predicate P is false if the argument x is none, and otherwise trivially true. The first statement of the method inhales P(write), which should be equivalent to inhale true, not affecting the program state. In the second statement, instead of unfolding P(write) directly, we use the expression perm(P(write)) as the argument of the predicate location, which should evaluate to write. Therefore, the statement should just be unfold P(write), and inhale true as a result. However, according to Carbon’s implementation, it subtracts 1 from the mask of P(write), and uses the resultant mask to evaluate perm(P(write)) in inhale (by substitution), leading to the inhale of the body of P(none), which is false.
The following program demonstrates the bug.
Predicate
Pisfalseif the argumentxisnone, and otherwise triviallytrue. The first statement of the method inhalesP(write), which should be equivalent toinhale true, not affecting the program state. In the second statement, instead of unfoldingP(write)directly, we use the expressionperm(P(write))as the argument of the predicate location, which should evaluate towrite. Therefore, the statement should just beunfold P(write), and inhaletrueas a result. However, according to Carbon’s implementation, it subtracts 1 from the mask ofP(write), and uses the resultant mask to evaluateperm(P(write))in inhale (by substitution), leading to the inhale of the body ofP(none), which is false.