-
Notifications
You must be signed in to change notification settings - Fork 54
Add "Heap reference monotone" post condition for procedures that modify the Heap #1099
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
base: main2
Are you sure you want to change the base?
Changes from all commits
9f0ac52
b4967b9
b5dca53
9771219
d23b9b7
1fc62fd
725ee54
32dc6ec
a32340b
d1e920e
9335663
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -158,6 +158,23 @@ procedure datatypeField() | |
| // assert x == 4; | ||
| // } | ||
|
|
||
| procedure someWriteHeapProcedure(c: Container) returns () | ||
| opaque | ||
| modifies c | ||
| { | ||
| c#intValue := 5 | ||
| } | ||
| ; | ||
|
|
||
| procedure callerUsesAllocateTwo() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand this test. Shouldn't it be: |
||
| opaque | ||
| { | ||
| var c: Container; | ||
| var d: Container; | ||
| c := new Container; | ||
| someWriteHeapProcedure(c); | ||
| d := new Container; | ||
| assert c != d | ||
| procedure modifyHeapAndReturnMultiple(c: Container) returns (x: int, y: int, z: int) | ||
| opaque | ||
| ensures x == 1 && y == 2 && z == 3 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -68,7 +68,7 @@ procedure modifyContainerWildcard(c: Container) returns (i: int) | |
| }; | ||
|
|
||
| procedure modifyContainerWithoutPermission1(c: Container, d: Container) | ||
| // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: modifies clause does not hold | ||
| // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: modifies clause could not be proved | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This error message changed from This is a diagnostic quality regression caused by the additional monotonicity postcondition making the VC harder for the solver. The same regression occurs at lines 130 and 155. Please investigate whether the solver timeout can be avoided — e.g., by increasing the timeout for these VCs, or by structuring the postcondition differently so it doesn't interfere with the solver's ability to find counterexamples for unrelated assertions.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I acknowledge this one and have been woking with ATS to find a solution for it. It is more complicated than I think. |
||
| opaque | ||
| { | ||
| var i: int := modifyContainerWildcard(c) | ||
|
|
@@ -127,7 +127,7 @@ procedure modifiesWildcardBodilessCaller() | |
| var x: int := d#value; | ||
| modifiesWildcardBodiless(c, d); | ||
| assert x == d#value // this should fail because modifies * means anything can change | ||
| //^^^^^^^^^^^^^^^^^^^ error: assertion does not hold | ||
| //^^^^^^^^^^^^^^^^^^^ error: assertion could not be proved | ||
| }; | ||
|
|
||
| procedure modifiesWildcardWithBody(c: Container, d: Container) | ||
|
|
@@ -152,7 +152,7 @@ procedure modifiesWildcardAndSpecificCaller() | |
| var x: int := d#value; | ||
| modifiesWildcardAndSpecific(c, d); | ||
| assert x == d#value // fails because modifies * subsumes modifies c | ||
| //^^^^^^^^^^^^^^^^^^^ error: assertion does not hold | ||
| //^^^^^^^^^^^^^^^^^^^ error: assertion could not be proved | ||
| }; | ||
| " | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| \[ERROR\] procedure '__main__': expected 1 arguments, got 0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| test_class_decl.py(9, 4): ✅ pass - (CircularBuffer@__init__ requires) Type constraint of n | ||
| DETAIL: 1 passed, 0 failed, 0 inconclusive | ||
| test_class_decl.py(8, 0): ✅ pass - Heap reference counter monotone (main) | ||
| unknown location: ✅ pass - Heap reference counter monotone (__main__) | ||
| DETAIL: 3 passed, 0 failed, 0 inconclusive | ||
| RESULT: Analysis success |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,6 @@ | ||
| test_class_empty.py(5, 4): ✅ pass - callElimAssert_requires_4 | ||
| test_class_empty.py(6, 4): ✅ pass - empty class instantiated | ||
| DETAIL: 2 passed, 0 failed, 0 inconclusive | ||
| test_class_empty.py(4, 0): ✅ pass - Heap reference counter monotone (test) | ||
| unknown location: ✅ pass - Heap reference counter monotone (__main__) | ||
| DETAIL: 4 passed, 0 failed, 0 inconclusive | ||
| RESULT: Analysis success |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| test_class_field_any.py(2, 4): ✅ pass - Heap reference counter monotone (MyClass@__init__) | ||
| test_class_field_any.py(6, 0): ❓ unknown - assert(113) | ||
| DETAIL: 0 passed, 0 failed, 1 inconclusive | ||
| unknown location: ✅ pass - Heap reference counter monotone (__main__) | ||
| DETAIL: 2 passed, 0 failed, 1 inconclusive | ||
| RESULT: Inconclusive |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| DETAIL: 0 passed, 0 failed, 0 inconclusive | ||
| unknown location: ✔️ always true if reached - Heap reference counter monotone (__main__) | ||
| DETAIL: 1 passed, 0 failed, 0 inconclusive | ||
| RESULT: Analysis success |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| test_class_field_use.py(14, 4): ✔️ always true if reached - Check PMul exception | ||
| test_class_field_use.py(14, 4): ✔️ always true if reached - assert(302) | ||
| test_class_field_use.py(15, 4): ✔️ always true if reached - Doubling of buffer did not work | ||
| DETAIL: 3 passed, 0 failed, 0 inconclusive | ||
| test_class_field_use.py(12, 0): ✔️ always true if reached - Heap reference counter monotone (main) | ||
| DETAIL: 4 passed, 0 failed, 0 inconclusive | ||
| RESULT: Analysis success |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| test_class_inheritance_no_dispatch.py(25, 4): ❓ unknown - assert(714) | ||
| DETAIL: 0 passed, 0 failed, 1 inconclusive | ||
| unknown location: ✅ pass - Heap reference counter monotone (__main__) | ||
| DETAIL: 1 passed, 0 failed, 1 inconclusive | ||
| RESULT: Inconclusive |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| test_class_method_call_from_main.py(6, 4): ✅ pass - Heap reference counter monotone (Greeter@__init__) | ||
| test_class_method_call_from_main.py(10, 8): ❓ unknown - name must not be empty | ||
| test_class_method_call_from_main.py(9, 23): ❓ unknown - (Greeter@greet ensures) Return type constraint | ||
| test_class_method_call_from_main.py(14, 4): ✅ pass - (Greeter@__init__ requires) Type constraint of name | ||
| test_class_method_call_from_main.py(15, 4): ✅ pass - assert(415) | ||
| DETAIL: 2 passed, 0 failed, 2 inconclusive | ||
| unknown location: ✅ pass - Heap reference counter monotone (__main__) | ||
| DETAIL: 4 passed, 0 failed, 2 inconclusive | ||
| RESULT: Inconclusive |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| test_class_mixed_init.py(19, 0): ✔️ always true if reached - class with init | ||
| test_class_mixed_init.py(19, 0): ❓ unknown - class with init | ||
| DETAIL: 1 passed, 0 failed, 1 inconclusive | ||
| unknown location: ✔️ always true if reached - Heap reference counter monotone (__main__) | ||
| DETAIL: 2 passed, 0 failed, 1 inconclusive | ||
| RESULT: Inconclusive |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,6 @@ | ||
| test_class_no_init.py(5, 4): ✅ pass - callElimAssert_requires_4 | ||
| test_class_no_init.py(6, 4): ❓ unknown - class without __init__ | ||
| DETAIL: 1 passed, 0 failed, 1 inconclusive | ||
| test_class_no_init.py(4, 0): ✅ pass - Heap reference counter monotone (test) | ||
| unknown location: ✅ pass - Heap reference counter monotone (__main__) | ||
| DETAIL: 3 passed, 0 failed, 1 inconclusive | ||
| RESULT: Inconclusive |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,6 @@ | ||
| test_class_no_init_multi_field.py(7, 4): ✅ pass - callElimAssert_requires_4 | ||
| test_class_no_init_multi_field.py(8, 4): ✅ pass - class with multiple annotated fields no init | ||
| DETAIL: 2 passed, 0 failed, 0 inconclusive | ||
| test_class_no_init_multi_field.py(6, 0): ✅ pass - Heap reference counter monotone (test) | ||
| unknown location: ✅ pass - Heap reference counter monotone (__main__) | ||
| DETAIL: 4 passed, 0 failed, 0 inconclusive | ||
| RESULT: Analysis success |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| test_class_no_init_with_method.py(4, 23): ❓ unknown - (WithMethod@get_x ensures) Return type constraint | ||
| test_class_no_init_with_method.py(8, 4): ✅ pass - callElimAssert_requires_4 | ||
| test_class_no_init_with_method.py(9, 4): ✅ pass - class with method but no __init__ | ||
| DETAIL: 2 passed, 0 failed, 1 inconclusive | ||
| test_class_no_init_with_method.py(7, 0): ✅ pass - Heap reference counter monotone (test) | ||
| unknown location: ✅ pass - Heap reference counter monotone (__main__) | ||
| DETAIL: 4 passed, 0 failed, 1 inconclusive | ||
| RESULT: Inconclusive |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| test_composite_return.py(6, 4): ✅ pass - Heap reference counter monotone (MyService@__init__) | ||
| test_composite_return.py(10, 4): ✅ pass - (MyService@__init__ requires) Type constraint of name | ||
| DETAIL: 1 passed, 0 failed, 0 inconclusive | ||
| test_composite_return.py(9, 0): ✅ pass - Heap reference counter monotone (create_service) | ||
| DETAIL: 3 passed, 0 failed, 0 inconclusive | ||
| RESULT: Analysis success |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,7 @@ | ||
| test_field_write.py(4, 4): ✅ pass - Heap reference counter monotone (Cell@__init__) | ||
| test_field_write.py(8, 4): ✅ pass - (Cell@__init__ requires) Type constraint of val | ||
| test_field_write.py(10, 4): ✅ pass - field overwritten | ||
| DETAIL: 2 passed, 0 failed, 0 inconclusive | ||
| test_field_write.py(7, 0): ✅ pass - Heap reference counter monotone (test_oop_field_write) | ||
| unknown location: ✅ pass - Heap reference counter monotone (__main__) | ||
| DETAIL: 5 passed, 0 failed, 0 inconclusive | ||
| RESULT: Analysis success |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| test_heap_reference_monotone.py(2, 4): ✅ pass - Heap reference counter monotone (ClassA@__init__) | ||
| test_heap_reference_monotone.py(5, 0): ✅ pass - (ClassA@__init__ requires) Type constraint of n | ||
| test_heap_reference_monotone.py(6, 0): ✅ pass - (ClassA@__init__ requires) Type constraint of n | ||
| test_heap_reference_monotone.py(11, 0): ✅ pass - assert(128) | ||
| unknown location: ✅ pass - Heap reference counter monotone (__main__) | ||
| DETAIL: 5 passed, 0 failed, 0 inconclusive | ||
| RESULT: Analysis success |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,12 @@ | ||
| test_with_statement.py(17, 4): ✔️ always true if reached - assert(364) | ||
| test_with_statement.py(20, 4): ✔️ always true if reached - assert(426) | ||
| test_with_statement.py(15, 0): ✔️ always true if reached - Heap reference counter monotone (test_with_as) | ||
| test_with_statement.py(25, 8): ✔️ always true if reached - assert(525) | ||
| test_with_statement.py(26, 8): ✔️ always true if reached - assert(558) | ||
| test_with_statement.py(22, 0): ✔️ always true if reached - Heap reference counter monotone (test_with_no_as) | ||
| test_with_statement.py(32, 21): ✔️ always true if reached - Check PAdd exception | ||
| test_with_statement.py(32, 8): ✔️ always true if reached - assert(697) | ||
| test_with_statement.py(33, 8): ✔️ always true if reached - assert(724) | ||
| DETAIL: 7 passed, 0 failed, 0 inconclusive | ||
| test_with_statement.py(28, 0): ✔️ always true if reached - Heap reference counter monotone (test_with_multiple) | ||
| DETAIL: 10 passed, 0 failed, 0 inconclusive | ||
| RESULT: Analysis success |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,8 @@ | ||
| test_with_void_enter.py(2, 4): ✅ pass - Heap reference counter monotone (VoidManager@__init__) | ||
| test_with_void_enter.py(5, 4): ✅ pass - Heap reference counter monotone (VoidManager@__enter__) | ||
| test_with_void_enter.py(8, 4): ✅ pass - Heap reference counter monotone (VoidManager@__exit__) | ||
| test_with_void_enter.py(14, 8): ✅ pass - assert(272) | ||
| test_with_void_enter.py(15, 4): ✅ pass - assert(287) | ||
| DETAIL: 2 passed, 0 failed, 0 inconclusive | ||
| test_with_void_enter.py(11, 0): ✅ pass - Heap reference counter monotone (test_void_enter) | ||
| DETAIL: 6 passed, 0 failed, 0 inconclusive | ||
| RESULT: Analysis success |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| class ClassA: | ||
| def __init__(self, n: int): | ||
| self.val : int = n | ||
|
|
||
| a1 = ClassA(1) | ||
| a2 = ClassA(2) | ||
|
|
||
| a1.val = 1 | ||
| a2.val = 2 | ||
|
|
||
| assert a1.val != a2.val | ||
|
thanhnguyen-aws marked this conversation as resolved.
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to set
free := truehere ? I thinkmonoCondholds by construction