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

Check by default that all pure and ghost functions have termination measures #718

Merged
merged 7 commits into from
Jan 12, 2024

Conversation

jcp19
Copy link
Contributor

@jcp19 jcp19 commented Jan 11, 2024

In the past, we run into unsoundnesses and tricky corner cases of Gobra because, so far, we were able to use non-terminating functions in specifications. This PR changes the default behaviour of Gobra to expect a termination measure in any pure function or method. Please let me know if you agree with this being the default behaviour. Notice that I did not adapt all of the current tests. This can be done but it would take more time than I am willing to spend atm.

@jcp19 jcp19 marked this pull request as draft January 11, 2024 20:40
@jcp19 jcp19 linked an issue Jan 11, 2024 that may be closed by this pull request
@jcp19 jcp19 marked this pull request as ready for review January 11, 2024 21:20
Copy link
Member

@ArquintL ArquintL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left some comments

@@ -177,13 +178,15 @@ pure func Join(elems []string, sep string) (res string) /*{
// HasPrefix tests whether the string s begins with prefix.
pure
ensures ret == (len(s) >= len(prefix) && s[0:len(prefix)] == prefix)
decreases _
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
decreases _
decreases

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to be consistent, i.e., to use decreases _ for abstract functions and decreases (or an appropriate non-constant measure) for non-abstract functions

Copy link
Contributor Author

@jcp19 jcp19 Jan 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about using decreases and dismissed it because these functions are imported and re-verified in every client. It feels wasteful to reverify termination everywhere. Note that, while the same could be said about reverifying the body, including the definition of the function may be useful for clients (and, unfortunately, Gobra/Viper does not allow us to define a function without verifying its correctness).

Update: I guess that my answer still does not account for the inconsistency, considering that some functions in these libraries are checked for termination. I guess we should opt for one: either all functions in the standard library are assumed to terminate, or we check the termination of all of them. I will merge your suggestions for now, and later we may decide to remove all termination measures

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure whether we already do that but we could in principle turn decreases measures for imported pure functions into wildcard measures to avoid the additional overhead of re-verifying termination. I'd rather do this within Gobra as opposed to these stubs such that we can still verify the stubs (and thus check that they actually terminate)

src/main/resources/stubs/strings/strings.gobra Outdated Show resolved Hide resolved
src/main/scala/viper/gobra/frontend/Config.scala Outdated Show resolved Hide resolved
src/main/scala/viper/gobra/frontend/Config.scala Outdated Show resolved Hide resolved
}
val hasMeasureIfNeeded = config.disableCheckTerminationPureFns || spec.terminationMeasures.nonEmpty
val needsMeasureError =
error(member, "All pure functions must have termination measures, but none was found for this member.", !hasMeasureIfNeeded)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
error(member, "All pure functions must have termination measures, but none was found for this member.", !hasMeasureIfNeeded)
error(member, "All ghost methods and pure functions must have termination measures, but none was found for this member.", !hasMeasureIfNeeded)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While looking at this body, I thought that the error message only captures some of the cases but actually you're calling this function only for pure functions and methods. However, shouldn't we call this check also for ghost (impure) functions and methods?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be happy to make that change as well if the rest agrees. Tbh, I did not even consider that; instead, I was concerned about guaranteeing that our specifications are always meaningful, which may not be the case if they refer to non-terminating pure functions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed Gobra to now check termination on all ghost methods as well. This PR should be ready to merge as soon as the tests go through

@jcp19 jcp19 changed the title Check by default that all pure functions have termination measures Check by default that all pure and ghost functions have termination measures Jan 12, 2024
@jcp19 jcp19 merged commit 742b1b6 into master Jan 12, 2024
2 of 3 checks passed
@jcp19 jcp19 deleted the joao-check-well-founded-funcs branch January 12, 2024 22:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add flag to force total correctness in specifications
2 participants