Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot always prove that a method leaves a disjoint set of objects unmodified #608

Open
danmatichuk opened this issue Apr 30, 2020 · 1 comment
Assignees
Labels
kind: enhancement Enhancements, feature requests, etc. These are NOT bugs, but ways we can improve Dafny

Comments

@danmatichuk
Copy link
Collaborator

danmatichuk commented Apr 30, 2020

Given the following class:

  class MyClass{
    var i : int;
    method setInt(i : int)
      modifies {this}
      {this.i := i; }
}

I would expect the following to hold for any set of objs : set<object>:

myClass.setInt(i);
assert myClass !in objs ==> unchanged(objs);

However this is not able to be verified if objs is the result of an opaque function, either due to
having an undefined body or via the {:opaque} attribute.

function method someObjsUndefinedFunction() : set<object>
...
var objs := someObjsUndefinedFunction();
myClass.setInt(1);
assert myClass !in objs ==> unchanged(objs); // fails

Notably this works as expected if the field update occurs directly instead of through a method call.

function method someObjsUndefinedFunction() : set<object>
...
var objs := someObjsUndefinedFunction();
myClass.i := 1;
assert myClass !in objs ==> unchanged(objs); // succeeds

Adding the following (trivially-satisfied) postcondition to the method yields the expected result and successfully verifies in both cases:

    method setIntPlus(i : int)
      modifies {this}
      ensures forall objs : set<object> :: this !in objs ==> unchanged(objs) // always trivially true
      {this.i := i; }
@danmatichuk
Copy link
Collaborator Author

danmatichuk commented Apr 30, 2020

Full test file here:

class MyClass{
    var i : int;
    method setInt(i : int)
      modifies {this}
      {this.i := i; }

    method setIntPlus(i : int)
      modifies {this}
      ensures forall objs : set<object> :: this !in objs ==> unchanged(objs) // always trivially true
      {this.i := i; }

    protected static function method someObjsProtectedFunction() : set<object>
      { {} }
  }

method someObjsMethod() returns (ret : set<object>)

function method someObjsUndefinedFunction() : set<object>
function method someObjsDefinedFunction() : set<object>
  { {} }

function method {:opaque} someObjsOpaqueFunction() : set<object>
  { {} }

method test(obj : MyClass, objs : set<object>)
  modifies {obj}
{
  var objs2 := someObjsMethod();
  var objs3 := someObjsUndefinedFunction();
  var objs4 : set<object> := *;
  var objs5 := someObjsDefinedFunction();
  var objs6 := someObjsOpaqueFunction();
  var objs7 := MyClass.someObjsProtectedFunction();

  label L1:
  obj.i := 1;
  assert obj !in objs ==> unchanged@L1(objs);
  assert obj !in objs2 ==> unchanged@L1(objs2);
  assert obj !in objs3 ==> unchanged@L1(objs3);
  assert obj !in objs4 ==> unchanged@L1(objs4);
  assert obj !in objs5 ==> unchanged@L1(objs5);
  assert obj !in objs6 ==> unchanged@L1(objs6);
  assert obj !in objs7 ==> unchanged@L1(objs7);

  label L2:
  obj.setInt(1);
  assert obj !in objs ==> unchanged@L2(objs);
  assert obj !in objs2 ==> unchanged@L2(objs2);
  assert obj !in objs3 ==> unchanged@L2(objs3); // fails
  assert obj !in objs4 ==> unchanged@L2(objs4);
  assert obj !in objs5 ==> unchanged@L2(objs5);
  assert obj !in objs6 ==> unchanged@L2(objs6); // fails
  assert obj !in objs7 ==> unchanged@L2(objs7);

  label L3:
  obj.setIntPlus(1);
  assert obj !in objs ==> unchanged@L3(objs);
  assert obj !in objs2 ==> unchanged@L3(objs2);
  assert obj !in objs3 ==> unchanged@L3(objs3);
  assert obj !in objs4 ==> unchanged@L3(objs4);
  assert obj !in objs5 ==> unchanged@L3(objs5);
  assert obj !in objs6 ==> unchanged@L3(objs6);
  assert obj !in objs7 ==> unchanged@L3(objs7);
}

@acioc acioc added kind: enhancement Enhancements, feature requests, etc. These are NOT bugs, but ways we can improve Dafny and removed weakness labels Jun 22, 2020
@acioc acioc added this to the Post 3.0 milestone Jul 22, 2020
@robin-aws robin-aws removed this from the Post 3.1 milestone Sep 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: enhancement Enhancements, feature requests, etc. These are NOT bugs, but ways we can improve Dafny
Projects
None yet
Development

No branches or pull requests

4 participants