C's semantics also makes a lot of things which I would assume was "trivially true" fail verification. This isn't Frama-C's fault however, of course.
sounds really interesting, do you remember some concrete example? Not saying you're wrong or anything, just curious of what kind of code is hard to analyze like this.
∀a: a+1 > a
if the type of 'a' is 32 bit int. Similarly negate(a) ≠ -a for some numbers. function Increment(A : Integer) return Integer
with Post => Increment'Result = A + 1;
It would find the counterexample for the situation where A is equal to Integer'Last. So you'd need to add a precondition like: function Increment(A : Integer) return Integer
with Pre => A < Integer'Last,
Post => Increment'Result = A + 1;
(doing this from memory and not fluent, so syntax may be off but the idea isn't) /*@ ensures \result > a; */
int increment(int a) {
return a + 1;
}
you would change it to: /*@ requires a < INT_MAX;
ensures \result > a; */
int increment(int a) {
return a + 1;
}
But if this function has N call sites, you now have N problems: At every call site you must prove that the precondition holds."iff a =/= MAXINT"
You either make your spec up as you go along and don't check it as its hidden in the code, or provide it so that static analysis tools and/or things like tla+ can help confirm. There never was any getting around that regardless of language. The code follows from spec which both follow from requirements
for(int i = 0; i < n; i++) {..}
It looks like the invariant should be: 0 <= i < n
But if they mistyped the loop that would be wrong. You have to explicitly state your invariants. At best, you could detect them and ask for confirmation. And that's for an easy to detect case.Most of the time with Frama-C, all you have to provide is function pre- and post-conditions and loop invariants.
``` 0 <= i <= n ```
As the loop reaches this value to terminate. Else, we could not deduce for example that `i = n` at the end of the loop (`0 <= i <= n && !(i < n)`).
If I was proving that 0 + 1 + .. n = n(n+1)/2, I wouldn't say that whatever induction step I chose to use was "part of the theorem", would I?
I've used Frama-C ACSL+WP and it was incredibly painful to use to prove basically anything.
For me the main issue was that Frama-C can say 3 things about your specs: Yes, No, and Don't know. That means I have no idea where to start to debug my proof, especially as I'm already convinced that my proof works! This is inherent to computing weakest pre-condition AFAIK. I had to provide my own loop invariants, which is also a pain :-).
C's semantics also makes a lot of things which I would assume was "trivially true" fail verification. This isn't Frama-C's fault however, of course.
I haven't used the other plugins, perhaps there are better ones!
Type systems can be quite nice with regards to error messages, especially as the programmer themselves essentially derive their own granularity with regards to the domain and the proofs of the domain. But yes, we all have examples of absolutely terrible type system error messages.
The paradigm of making comments have semantic meaning in some other language is also terrible. I'd rather have a superset of the core language with syntactic extensions for proofs. The build system can pull out the core language source code for me.
Finally:
I think that abstract interpretation of a low-level compilation target combined with a proof-carrying compiler is the way to go. The compiler has proofs of a bunch of stuff regarding the code already, carry them down into the assembly level please! There's some work in abstract interpretation of WebAssembly, and I think that could be a great platform for formal verification.
Sorry for the barfing :-). Hopefully there're thoughts here to react to and reply to me about!