Consider the following code
int f(int a, int b){
return 0;
}
/*#
ensures (f(2,3)== 0) ==> \result == 2;
*/
int g() {
if (f(2,3) == 0)
return 2;
return 0;
}
The response of frama-c to the following code is the following error
[kernel:annot-error] fing.c:5: Warning:
unbound function f. Ignoring logic specification of function g
[kernel] User Error: warning annot-error treated as fatal error.
[kernel] User Error: stopping on file "fing.c" that has errors. Add '-kernel-msg-key pp'
for preprocessing command.
[kernel] Frama-C aborted: invalid user input.
Is there a way to write a specification where there's a call of a function inside an "if" clause ?
In ACSL, you cannot use a C function in the specification. If you want to do something like this, the only possibility is to define a logic function (ideally provably) equivalent to the C function and to use this logic function.
/*# logic integer l_f(integer a, integer b) = 0 ; */
//# ensures \result == l_f(a, b);
int f(int a, int b){
return 0;
}
/*#
ensures (l_f(2,3)== 0) ==> \result == 2;
*/
int g() {
if (f(2,3) == 0)
return 2;
return 0;
}
Related
The Rascal documentation has an example of a function that takes a function as an argument:
int f(int x, int (int) multi){ return multi(x); }
Conversely, what is the syntax for a function that returns a function?
I couldn't find an example and tried things along the line:
(int (int)) f() {return (int y) {return y;}}
but got syntax errors in the repl.
Here is an example:
int two(int n) = 2 * n;
int(int) g() = two;
Function two multiplies by 2 and g returns the function two.
Observe that the return type of g is int(int), a type describing a function which returns an int and has one int argument.
A similar effect can be achieved by an inline definition:
int(int) g() = int(int n) { return 2 * n; };
You can also use this same notation inside other functions. For instance, you could create a function which multiplies two numbers:
int mult(int n, int m) = n * m;
If you use it, you would get what you would expect:
rascal>mult(3,4);
int: 12
You can instead return a function that essentially partially applies this function as follows:
int(int) multBy(int n) {
return int(int m) {
return mult(n,m);
};
}
int (int) (int)
So, this returns a function that takes an int and returns an int (int), i.e., a function that takes an int and returns an int. You can then use it as so:
rascal>multBy3 = multBy(3);
int (int)
rascal>multBy3(4);
int: 12
You can find more examples in some of our (many) files with tests:
lang::rascal::tests::basic::Functions
lang::rascal::tests::functionality::FunctionComposition
Thanks for your question, we have more documentation to do!
The short answer to my failed attempt is:
leave out the outermost parens in the return type of f
add the return type int of the anonymous function that is returned by f
don't forget the semi after f's return statement
That gives:
int (int) f() { return int (int y) { return y; } ; }
Consider the following code:
template<int... V>
static constexpr int f(int v) {
int a[] = { (v ^= V, 0)... }; // Line 3
return v;
}
static constexpr int i = f<0x00>(0x11); // Line 7
int main() { }
It compiles with GCC and fails to compile with clang with the following error:
main.cpp:7:22: error: constexpr variable 'i' must be initialized by a constant expression
[...]
main.cpp:3:23: note: subexpression not valid in a constant expression
Note that it doesn't depend on the fact that I'm using a template function.
In other terms, neither the code above nor the one below compile with clang:
static constexpr int mix(int v, int u) {
int a[] = { (v ^= u, 0) };
return v;
}
static constexpr int mf = mix(0x11, 0x00);
int main() { }
Which compiler is right?
As mentioned here, it is a bug of clang:
the bug is something odd about the left-hand side of a comma operator
Confirmed and fixed.
This code doesn't compile, I don't get why:
struct C { int a;};
void foo(C c, int s)
{
cout << c.a << s;
}
int main()
{
std::function<void(C,int)> call = std::bind(&foo,std::placeholders::_1,5);
C c;
c.a = 5;
call(c);
return 0;
}
I get:
No match for call to std::function<void(C,int)> (C&)
The bind() expression std::bind(&foo, _1, 5) produces a unary function. You try to use a unary function to initialize a binary std::function<void(c, int)>. Did you mean to use something like this?
std::function<void(C)> call = std::bind(&foo, _1, 5);
I have the following sample code:
typedef struct {
BYTE fs_type; /* FAT sub-type (0:Not mounted) */
BYTE drv; /* Physical drive number */
} FATFS_temp;
FATFS_temp *FatFs_temp[1]; /* Pointer to the file system objects (logical drives) */
/*#
# requires (vol <= 0) && (fs != \null) ==> \valid((fs)) ; // problematic one
# behavior mount:
# //assumes \valid(fs) && vol <= 0;
# assumes fs != \null && vol <= 0;
# ensures (vol <= 0) ==> (FatFs_temp[vol] == \old(fs));
# ensures fs->fs_type == 0;
# behavior unmount:
# assumes fs == \null && vol <= 0;
# ensures (vol <= 0) ==> (FatFs_temp[vol] == \null);
# behavior error:
# assumes vol > 0;
# ensures \result == 88;
# complete behaviors mount, unmount, error;
# disjoint behaviors mount, unmount, error;
*/
int f_mount_temp (
BYTE vol, /* Logical drive number to be mounted/unmounted */
FATFS_temp *fs /* Pointer to new file system object (NULL for unmount)*/
)
{
FATFS_temp *rfs;
if (vol >= 1) /* Check if the drive number is valid */
return 88;
rfs = FatFs_temp[vol]; /* Get current fs object */
if (rfs) {
rfs->fs_type = 0; /* Clear old fs object */
}
if (fs) {
fs->fs_type = 0; /* Clear new fs object */
}
FatFs_temp[vol] = fs; /* Register new fs object */
return 22;
}
But Frama-C / Why3 couldn't prove one of the 'requires' as commented in the code.
the .Why file states the following:
goal WP "expl:Pre-condition (file src/ff_temp.c, line 12) in 'f_mount_temp'":
forall vol_0 : int.
forall malloc_0 : map int int.
forall fatFs_temp_0 : map int addr.
forall fs_0 : addr.
(fs_0 <> null) ->
(vol_0 <= 0) ->
((linked malloc_0)) ->
((is_uint8 vol_0)) ->
(forall k_0 : int. (0 <= k_0) -> (k_0 <= 0) -> (null = fatFs_temp_0[k_0])) ->
((valid_rw malloc_0 fs_0 2))
end
for the sake of learning, my questions are:
1) what is wrong with that pre-condition?
2) based on the outputs in the .Why file, what should my approach be to find out whats wrong?
3) can someone point me to resources to learn how to go about debugging my function contracts?
EDIT:
i ran Frama-c with the following flags: "-wp -wp-rte -wp-fct f_mount_temp"
i did not call this f_mount_temp from elsewhere. i ran Frama-c to check on this f_mount_temp() directly.
now its clearer to me, its likely the additional assertions that caused the pre-condition to fail. the processed function contracts are the following, with the comments indicating the status of each assertion:
/*# requires vol ≤ 0 ∧ fs ≢ \null ⇒ \valid(fs); // unknown
behavior mount: // unknown
assumes fs ≢ \null ∧ vol ≤ 0;
ensures \old(vol) ≤ 0 ⇒ FatFs_temp[\old(vol)] ≡ \old(fs);
ensures \old(fs)->fs_type ≡ 0;
behavior unmount: //unknown
assumes fs ≡ \null ∧ vol ≤ 0;
ensures \old(vol) ≤ 0 ⇒ FatFs_temp[\old(vol)] ≡ \null;
behavior error: //unknown
assumes vol > 0;
ensures \result ≡ 88;
complete behaviors mount, unmount, error; // green
disjoint behaviors mount, unmount, error; // green
*/
the inline assertions added by the -wp-rfe flags are:
int f_mount_temp(BYTE vol, FATFS_temp *fs) {
int __retres;
FATFS_temp *rfs;
if ((int)vol >= 1) {
__retres = 88;
goto return_label;
}
/*# assert rte: index_bound: vol < 1; */ // ok
rfs = FatFs_temp[vol];
if (rfs) {
/*# assert rte: mem_access: \valid(&rfs->fs_type); */ //unknown
rfs->fs_type = (unsigned char)0;
}
if (fs) {
/*# assert rte: mem_access: \valid(&fs->fs_type); */ // unknown
fs->fs_type = (unsigned char)0;
}
/*# assert rte: index_bound: vol < 1; */ // unknown
FatFs_temp[vol] = fs;
__retres = 22;
return_label: return __retres;
}
1) what is wrong with that pre-condition?
You are using && and ==> as if their relative precedences were well-known. This is wrong from a human point of view, because as ==> does not appear in many languages other than ACSL, only ACSL specialists can know what a formula that depends on its precedence means.
Apart from that, there can never be anything wrong with a pre-condition in a code snippet that does not involve a call to the function. The pre-condition it not a property that is proved with respect to the implementation of the function but with respect to the context in which the function is used. You could have made a mistake and written the logical equivalent of \false and the pre-condition would still be fine for your snippet (it would only mean that all calls to the function are invalid and must themselves be proved to be unreachable).
For your question to make sense, it would have to either:
involve the proof (or lack of proof) of a post-condition of f_mount_temp and provide this function's implementation, or
involve the proof (or lack of proof) of a pre-condition of f_mount_temp and the code of the function in which f_mount_temp is called, including that function's pre-conditions, so that it is possible to tell whether this calling function respects f_mount_temp's pre-condition. In this latter case it is not necessary to provide f_mount_temp's code or post-condition, unless it is called several times in the caller. Also the code of the other functions called from the caller need not be provided, but their contracts should be.
What you have done here, providing f's code and asking why f's pre-condition is not proved, is not coherent.
2) based on the outputs in the .Why file, what should my approach be to find out whats wrong?
This is not a bad place to ask, and I think that you could receive help if you ask again with the right bits of information.
3) can someone point me to resources to learn how to go about debugging my function contracts?
I am not aware of many of these, but this site could become a resource explaining the most common debugging tricks if you ask again…
I'd like to know if it's possible to do some kind of forward conditioned slicing with Frama-C and I'm playing with some examples to understand how one could achieve this.
I've got this simple example which seems to result in an imprecise slice and I can't understand why. Here is the function I'd like to slice :
int f(int a){
int x;
if(a == 0)
x = 0;
else if(a != 0)
x = 1;
return x;
}
If I use this specification :
/*# requires a == 0;
# ensures \old(a) == a;
# ensures \result == 0;
*/
then Frama-C returns the following slice (which is precise), using "f -slice-return" criterion and f as entry point :
/*# ensures \result ≡ 0; */
int f(void){
int x;
x = 0;
return x;
}
But when using this specification :
/*# requires a != 0;
# ensures \old(a) == a;
# ensures \result == 1;
*/
then all instructions (& annotations) remain (when I was waiting for this slice to be returned :
/*# ensures \result ≡ 1; */
int f(void){
int x;
x = 1;
return x;
}
)
In the last case, is the slice imprecise? In this case, what could be the cause?
Regards,
Romain
Edit : I wrote "else if(a != 0) ..." but the problem remains with "else ..."
In Frama-C, the slicing plug-in relies on the result of a preliminary static analysis plug-in called the value analysis.
This value analysis can represent the values for variable a when a == 0 (the set of values is in this case { 0 }) but has a hard time to represent the values for a when it is known that a != 0. In the latter case, if a is not already known to be positive or negative, the value analysis plug-in needs to approximate the set of values for a. If a was known to be positive, for instance if it was an unsigned int, then the nonzero values could be represented as an interval, but the value analysis plug-in cannot represent “all values of type int except 0”.
If you are willing to change the pre-condition, you can write it in a form that is more easily understood by the value analysis plug-in (together with value analysis option -slevel):
$ cat t.c
/*# requires a < 0 || a > 0 ;
# ensures \old(a) == a;
# ensures \result == 0;
*/
int f(int a){
int x;
if(a == 0)
x = 0;
else if(a != 0)
x = 1;
return x;
}
$ frama-c -slevel 10 t.c -main f -slice-return f -then-on 'Slicing export' -print
…
/* Generated by Frama-C */
/*# ensures \result ≡ 0; */
int f(void)
{
int x;
x = 1;
return x;
}
This has no relevance whatsoever with your main question, but your ensures a == \old(a) clause is not doing what you expect. If you pretty-print your source code with option -print, you will see it has been silently transformed into ensures \old(a) == \old(a).
The ACSL language does not permit referring about the value of formal variables in the post-state, mostly because this is meaningless from the point of view of the caller. (The stack frame of the callee is popped after the call terminates.)