-
Notifications
You must be signed in to change notification settings - Fork 262
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
{:termination false} also allows incorrect implementations of trait functions #2500
Comments
This seems to be a result of the verification condition generated for the override check assuming that the functions defined on the trait and the class are equivalent (the implementation {:verboseName "B.Class.TotallyNotZero (override check)"} OverrideCheck$$B.Class.TotallyNotZero(this: ref) returns (ret#0: int)
{
var Class_$_Frame: <beta>[ref,Field beta]bool;
assert true;
Class_$_Frame := (lambda<alpha> $o: ref, $f: Field alpha ::
$o != null && read($Heap, $o, alloc) ==> false);
assert (forall<alpha> $o: ref, $f: Field alpha :: false ==> false);
assume B.Class.TotallyNotZero(this) == A.Trait.TotallyNotZero(this); <--
assume B.Class.TotallyNotZero(this) == ret#0;
assert ret#0 != 0;
} When |
Note the "workaround" to this is to always copy the specifications on trait elements onto the implementing elements in any implementing class. |
Some more notes on this issue: The
If we remove the assume the trigger for it also goes away, but depending on triggers for correctness is icky. … and because (2) the spec of the predicate can also be written as The source of the problem seems to be related to termination metrics. Specifically, because of
The version in
The result is that the following verifies:
|
Reclassifying this away from soundness, since it depends on The fixes here are either
|
Not verifying yet!
I'm classifying this back to This is not the intent of this feature, at least based on what the docs say:
(emphasis mine) So we should fix the docs or fix the feature, but the current situation seems akin to saying " |
Today @fabiomadge and I discussed about this issue. The following example shows why "just" locking the consequence axiom of the trait function under a context height constraint is not enough:
This example verifies even if the consequence axiom is removed from the Boogie module that we generate for B. |
One thing that we didn't explore in depth is whether it would be possible to rewrite the override check to remove all mentions of the trait and the class function, and instead just prove |
It isn't valid when checking termination, though. |
PR was reverted for completeness issues |
We strengthen this check by performing it on the visibility level of the implementing function, but restricting the enabled axiom to the callers of the trait. To achieve this, we add the canCall precondition to the axiom. Additionally, we consider imported trait functions when computing the visibility levels. Fixes #2500. <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small>
Classes are not allowed to extend a trait in another module unless
{:termination false}
is present on the trait. The details of the unsoundness this avoids are in this issue: #1588The implication of this attribute is only that a failure to terminate might not be caught by the verifier, but there also seem to be other cases not strictly related to termination proof conditions:
Moving the
Trait
trait inside module B causes the missing post-condition onClass.TotallyNotZero
to be flagged correctly.This may be by design because of the limitations of modular verification, but at the very least
{:termination false}
needs to be documented much better regardless. The name also does not imply opting in to this kind of unsoundness.The text was updated successfully, but these errors were encountered: