I am a newbie user of Frama-C and have a few questions regarding assertions over pointers.
Consider the C fragment below involving:
- two related data structures Data and Handle, s.t. Handle has a pointer to Data;
- a 'state' field in Data indicating whether some hypothetical operation has completed
- three functions: init(), start_operation() and wait();
- a main() function using the above, and containing 6 assertions (A1-A6)
Now, why is it that A5 and A6 cannot be asserted with the WP verifier ("frama-c -wp file.c") Shouldn't they hold due to the last "ensures" clause on start_operation()?
What am I doing wrong?
Best,
Eduardo
typedef enum
{
PENDING, NOT_PENDING
} DataState;
typedef struct
{
DataState state;
int value;
} Data;
typedef struct
{
Data* data;
int id;
} Handle;
/*@
@ ensures \valid(\result);
@ ensures \result->state == NOT_PENDING;
@*/
Data* init(void);
/*@
@ requires data->state == NOT_PENDING;
@ ensures data->state == PENDING;
@ ensures \result->data == data;
@*/
Handle* start_operation(Data* data, int to);
/*@
@ requires handle->data->state == PENDING;
@ ensures handle->data->state == NOT_PENDING;
@ ensures handle->data == \old(handle)->data;
@*/
void wait(Handle* handle);
int main(int argc, char** argv)
{
Data* data = init();
/*@ assert A1: data->state == NOT_PENDING; */
Handle* h = start_operation(data,0);
/*@ assert A2: data->state == PENDING; */
/*@ assert A3: h->data == data; */
wait(h);
/*@ assert A4: h->data->state == NOT_PENDING; */
/*@ assert A5: data->state == NOT_PENDING; */
/*@ assert A6: h->data == data; */
return 0;
}
You are verifying some tricky memory manipulations for a “newbie”.
The ACSL construct
\old
does not work exactly like you think it does.First,
\old(handle)
in a post-condition is the same ashandle
, becausehandle
is a parameter. A contract is intended to be used from the point of view of callers. Even if the functionwait
modifiedhandle
(which would be unusual but is possible), its contract would still be intended to relate values passed as argument by the caller and the state returned by the function to the caller.In short, in an ACSL post-condition,
parameter
always means\old(parameter)
(even if the function modifiesparameter
like a local variable).Second, the rule above is only for parameters. For global variables and memory accesses, the post-condition is considered to apply to the post-state, as you would expect from its name. The construct
\old(handle)->data
that you wrote, and that is equivalent tohandle->data
, means “the field.data
that the old value of handle points to in the new state”, so that the post-conditionhandle->data == \old(handle)->data
is a tautology and probably not what you intended.From the context, it appears that you intended
handle->data == \old(handle->data)
instead, which means "the field.data
that the old value ofhandle
points to in the new state is equal to the field.data
that the old value ofhandle
points to in the old state”. With that change, all the assertions in your program get proved for me (using Alt-Ergo 0.93).