I can't think of any idea to get foo's assigns clause to be proved. I tried assigns var; since foo() indirectly modifies the global var variable, but it doesn't work. Is there a way to get an assigns clause for the local p variable or the location return from a()? Here is the code:
int var;
//# assigns \nothing;
int *a(){
return &var;
}
//# assigns *p;
void b(int* p){
*p = 1;
}
//# assigns \nothing;
void foo(){
int *p = a();
b(p);
}
//# assigns var;
void main(){
var = 0;
foo();
return;
}
frama-c command:
frama-c -wp test.c
[kernel] Parsing test.c (with preprocessing)
[wp] Warning: Missing RTE guards
[wp] 10 goals scheduled
[wp] [Alt-Ergo] Goal typed_foo_assign_normal_part3 : Unknown (103ms)
[wp] [Alt-Ergo] Goal typed_foo_assign_exit_part3 : Unknown (Qed:4ms) (102ms)
[wp] Proved goals: 8 / 10
Qed: 8
Alt-Ergo: 0 (unknown: 2)
As you guessed, foo does assign something, and assigns \nothing is an invalid clause for this function. The proper clause is indeed assigns var. Within an assigns clause, you must list all global variables that are modified, plus all the variables that are local to a caller and that can be reference through a formal.
Now, why does the proof of the variants with assigns var not go through? Well, as written, in foo, WP cannot guess where p points to, as it has no way of knowing that it is actually equal to &a. You must add this information to the specification of function a. With this modification, the proof is immediate.
Full code:
int var;
/*# assigns \nothing;
ensures \result == &var; */
int *a(){
return &var;
}
//# assigns *p;
void b(int* p){
*p = 1;
}
//# assigns var;
void foo(){
int *p = a();
b(p);
}
//# assigns var;
void main(){
var = 0;
foo();
return;
}
Related
I am shifting from Python to C so bit rusty on the semantics as well as coding habit. In Python everything is treated as an object and objects are passed to functions. This is not the case in C so I want to increment an integer using pointers. What is the correct assignment to do so. I want to do it the following way but have the assignments wrong:
#include <stdio.h>
int i = 24;
int increment(*i){
*i++;
return i;
}
int main() {
increment(&i);
printf("i = %d, i);
return 0;
}
I fixed your program:
#include <stdio.h>
int i = 24;
// changed from i to j in order to avoid confusion.
// note you could declare the return type as void instead
int increment(int *j){
(*j)++;
return *j;
}
int main() {
increment(&i);
printf("i = %d", i);
return 0;
}
Your main error was the missing int in the function's argument (also a missing " in the printf).
Also I would prefer using parentheses in expressions as *j++ and specify exactly the precedence like I did in (*j)++, because I want to increment the content of the variable in the 'j' location not to increment the pointer - meaning to point it on the next memory cell - and then use its content.
I was trying to implement pwd command in xv6 system. But i am getting a error in sysfile.c execution. The function is as follows showing the error:-
int sys_getcwd(void) {
char *p;
int n;
if(argint(1, &n) < 0 || argptr(0, &p, n) < 0)
return -1;
return name_for_inode(p, n, proc->cwd);
}
I get error as follows:
error: ‘proc’ undeclared (first use in this function)
return name_for_inode(p, n, proc->cwd);
But I also included proc.h in this file.
proc is not defined, and warning, it's a struct name.
You have to query the current process, you can do it with myproc() function
int sys_getcwd(void) {
char *p;
int n;
struct proc *curproc = myproc();
if(argint(1, &n) < 0 || argptr(0, &p, n) < 0)
return -1;
return name_for_inode(p, n, curproc->cwd);
}
Yes proc is not global variable so initialize it with current process on which cpu is working.
struct proc *proc = myproc();
return name_for_inode(p, n, proc->cwd);
Frama-C considers the code below correct (no warning, no error) :
#include <stdio.h>
#include <stdlib.h>
int *p;
int main() {
p = malloc(sizeof(int));
if (p!=NULL) {
*p = 9;
printf("*p = %d\n",(int) (*p));
}
return(1);
}
But, if I change slightly the code by splitting the if-then-else:
#include <stdio.h>
#include <stdlib.h>
int *p;
int main() {
p = malloc(sizeof(int));
if (p!=NULL) {
*p = 9;
}
if (p!=NULL) {
printf("*p = %d\n",(int) (*p));
}
return(1);
}
I get the message :
test6.c:13:[value] warning: accessing uninitialized left-value. assert \initialized(p);
And the question is, why is Frama-C considering that p might access an uninitialized left-value? What am I missing?
I invoke Frama-C using the command:
frama-c-gui -val test.c
Abstract interpreters limit the complexity of their analysis by performing abstractions ("joins") when two control-flow paths meet. This is what happens on your second example: after the end of the first if, the abstractions for the two branches are joined. In the resulting abstraction, the relationship between p and the initialization of *p is lost.
In Frama-C/Eva, it is possible not to perform joins when multiple control-flow paths meet, instead propagating sets of states in parallel. The maximum cardinality of those sets is governed by the parameter -slevel. Here -slevel 2 is sufficient to prove your second example.
I've started learning C for Arduino for about 2 weeks. I have the following code and I don't understand how data is retrieved from function ReadLine. Also I don't understand how variable BufferCount affects the program and why it is used. I do know that it holds the number of digits the year have but that's about all I know about this variable.
From what I've learned so far a function is composed of:
function type specifier
function name
function arguments.
What I see in this program makes me think that the function can also return values using the argument part. I always thought that a function can only return a value that is the same type (int, boolean ...) as the type specifier.
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.avaible() > 0) {
int bufferCount;
int year;
char myData[20];
bufferCount = ReadLine (myData);
year = atoi(myData); //convert string to int
Serial.print("Year: ");
Serial.print(year);
if (IsLeapYear(year)) {
Serial.print(" is ");
} else {
Serial.print(" is not ");
}
Serial.println("a leap year");
}
}
int IsLeapYear(int yr) {
if (yr % 4 == 0 && yr % 100 != 0 || yr % 400 == 0) {
return 1; //it's a leap year
} else {
return 0;
}
}
int ReadLine (char str[]) {
char c;
int index = 0;
while (true) {
if (Serial.available() > 0) {
c = Serial.read();
if (c != '\n') {
str[index++] = c;
} else {
str[index] = '\0'; //null termination character
break;
}
}
}
return index;
}
The fundamental concept you are missing is pointers. In the case of a function like isLeapYear there, you'd be right about that parameter. It is just a copy of the data from whatever variable was passed in when the function gets called.
But with ReadLine things are different. ReadLine is getting a pointer to a char array. A pointer is a special kind of variable that holds the memory address of another variable. And it is true that in this case you are getting a local copy of the pointer, but it still points to the same location in memory. And during the function, data is copied not into the variable str, but to the memory location it points to. Since that is a memory location that belongs to a variable in the scope of the calling function, that actual variable's value will be changed. You've written over it in memory.
I am trying to prove quantified assertions for arrays and encountered some problems. Consider the following small program:
int a[4] = {1,2,3,4};
/*# requires p == a;
assigns \nothing;
*/
void test(int *p)
{
p++;
//# assert \forall int i; 0 <= i < 3 ==> p[i] < 10;
//# assert \exists int i; p[i] == 3;
}
I am using the 'Typed' memory model:
frama-c-gui -wp -wp-qed -wp-byreference -wp-model 'Typed' -main test Test.c
For some reason the "requires" does not hold and thus all assertions can be proved, even 1==2. In order to overcome this I directly assign the global variable in the function body:
int a[4] = {1,2,3,4};
/*# assigns \nothing;
*/
void test(int *p)
{
p = a;
p++;
//# assert \forall int i; 0 <= i < 3 ==> p[i] < 10;
//# assert \exists int i; p[i] == 3;
}
Here the forall holds but the exists does not. The exists only holds when I add the assertion "p[1] == 3" before it. What is missing to prove such existential array properties? I need this to express a loop invariant for a search loop over array entries.
Thanks, Harald
The "requires" is transformed into false by an incorrect simplification. It will be corrected in the next release. Thank you for spotting the error.
With the fix, the last assertion is still not proved by Alt-ergo because it is not able to find the witness for i using its usual heuristics. When you add the assertion "p[1] == 3" you give the witness, that's why it's easier to prove. Some other provers (Z3, CVC4) will be able to prove this particular assertion directly. Stay tuned for the next release.