假设我们有这样一个数据结构:
#typedef struct
{
int C_Field;
}C;
#typedef struct
{
C B_Array[MAX_SIZE];
}B;
#typedef struct
{
B A_Array[MAX_SIZE];
}A;
在下面的示例中,Frama-C 似乎没有为 C 类型结构体的字段分配位置:
/*@
assigns Arg->A_Array[0..(MAX_SIZE - 1)].B_Array[0..(MAX_SIZE - 1)].C_Field;
*/
void Initialize (A * Arg);
Frama-C 是否接受上述注释?
代码详述如下。主要目标是将字段 C_Field 重置为 0:
/*@ predicate
ResetB (B * Arg) =
\forall integer Index; 0<= Index < MAX_SIZE ==>
Arg -> B_Array[Index].C_Field == 0;
*/
//@ assigns * Arg;
// Even I tried this:
//@ assigns Arg -> A_Array[0..(MAX_SIZE - 1)];
void Initialize (A * Arg)
{
/*@ loop invariant 0 <= Index <= MAX_SIZE;
loop invariant ResetB(&(Arg->A_Array[Index]));
loop assigns Index, Arg -> A_Array[0..(MAX_SIZE - 1)];
*/
for (int Index = 0; Index < MAX_SIZE; Index++)
{
Reset(&(Arg -> A_Array[Index]));
}
}
/*@ assigns Arg -> B_Array[0..(MAX_SIZE - 1)];
ensures ResetB(Arg);
*/
void Reset(B * Arg)
{
/*@ loop invariant 0 <= Index <= MAX_SIZE;
loop invariant \forall integer i; 0<= i < Index ==>
Arg -> B_Array[i].C_Field == 0;
loop assigns Index, Arg -> B_Array[0..(MAX_SIZE - 1)];
*/
for (int Index = 0; Index < MAX_SIZE; Index++)
{
Arg -> B_Array[Index].C_Field = 0;
}
}
满足函数 Reset 的约定,但未满足函数 Initialize 的约定。如何为初始化合约编写正确的“分配”?
最佳答案
假设您正在使用插件 WP(请参阅上面的评论),您的主要问题是您还没有编写 loop assigns
对于 Initialize
中的循环功能。 loop assigns
对于您想要使用 WP 的函数中出现的每个循环都是必需的。另外,如果您的契约(Contract)有ensures
条款,您很可能需要 loop invariant
,再次针对正在分析的代码中的每个循环。
更新
使用您提供的代码和 frama-c Silicon,唯一没有用 frama-c -wp file.c
证明的东西是 Initialize
中的循环不变式关于ResetB
。之所以没有被证明,是因为它是错误的。真正的不变量应该是 \forall integer i; 0<=i<Index ==> ResetB(&(Arg->A_Array[i]))
。通过以下完整示例,所有内容都会被放电,至少对于硅来说是这样:
#define MAX_SIZE 100
typedef struct
{
int C_Field;
int D_Field;
}C;
typedef struct
{
C B_Array[MAX_SIZE];
}B;
typedef struct
{
B A_Array[MAX_SIZE];
}A;
/*@ predicate
ResetB (B * Arg) =
\forall integer Index; 0<= Index < MAX_SIZE ==>
Arg -> B_Array[Index].C_Field == 0;
*/
void Reset(B * Arg);
// @ assigns * Arg;
// Even I tried this:
//@ assigns Arg -> A_Array[0..(MAX_SIZE - 1)];
void Initialize (A * Arg)
{
/*@ loop invariant 0 <= Index <= MAX_SIZE;
loop invariant \forall integer i; 0<=i<Index ==> ResetB(&(Arg->A_Array[i]));
loop assigns Index, Arg -> A_Array[0..(MAX_SIZE - 1)];
*/
for (int Index = 0; Index < MAX_SIZE; Index++)
{
Reset(&(Arg -> A_Array[Index]));
}
}
/*@ assigns Arg -> B_Array[0..(MAX_SIZE - 1)];
ensures ResetB(Arg);
*/
void Reset(B * Arg)
{
/*@ loop invariant 0 <= Index <= MAX_SIZE;
loop invariant \forall integer i; 0<= i < Index ==>
Arg -> B_Array[i].C_Field == 0;
loop assigns Index, Arg -> B_Array[0..(MAX_SIZE - 1)];
*/
for (int Index = 0; Index < MAX_SIZE; Index++)
{
Arg -> B_Array[Index].C_Field = 0;
}
}
关于static-analysis - ACSL "assigns"C 代码内部结构和字段的注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43648733/