viperproject/silicon

Example of quantified permissions not matching carbon

ejconlon opened this issue · 3 comments

The following program verifies under carbon but not silicon:

Loop invariant (forall r: Ref :: { r.next } (r in nodes) ==> acc(r.next, write)) && (forall r: Ref :: { r.next } (r in nodes) ==> acc(r.val, write)) && (forall r: Ref :: { r.next } (r in nodes) ==> r.next != null ==> (r.next in nodes)) might not hold on entry. There might be insufficient permission to access r.val (cyclic.vpr@36.22--36.23) (cached)

It does work with the trigger r in nodes or when the triggers are removed.

method isCyclic(nodes: Set[Ref], root: Ref) returns (cyclic: Bool)
  requires root in nodes
  requires (forall r: Ref :: {r.next} r in nodes ==> acc(r.next) && acc(r.val) && (r.next != null ==> r.next in nodes))
{
  var seen: Set[Ref] := Set(root)
  var current: Ref := root

  while (current.next != null && !(current.next in seen))
    invariant current in nodes
    invariant (forall r: Ref :: {r.next} r in nodes ==> acc(r.next) && acc(r.val) && (r.next != null ==> r.next in nodes))
  {
    seen := seen union Set(current.next)
    current := current.next
  }

  cyclic := (current.next != null)
}

Interestingly, it seems to also verify when the triggers are made {r.next}{r.val} - without r.val as a trigger there seems to be a difficulty in finding the permissions to r.val that are needed for establishing the loop invariant.

If I remember correctly, heap-dependent triggers are currently not inferred by Silver's trigger inference code, and thus need to be provided manually.

Hi Malte,

Thanks - that explains why some triggers are needed (although in this example other choices will get made by Viper if we leave triggers out, that unfortunately lead to matching loops); it's less clear to me why both triggers are necessary. I have an idea, but suspect this has to do with the way we desugar quantified permissions internally (which ideally wouldn't be visible to a user..)