我有以下示例代码:
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;
}
但Frama-C / Why3无法证明代码中评论的“要求”之一。 .Why文件说明如下:
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
为了学习,我的问题是:
1)这种先决条件有什么问题?
2)根据.Why文件中的输出,我的方法应该是找出什么错误?
3)有人可以指点资源来学习如何调试我的函数合约吗?修改
我使用以下标志运行Frama-c:“ - wp -wp-rte -wp-fct f_mount_temp” 我没有从其他地方调用这个f_mount_temp。我运行Frama-c直接检查这个f_mount_temp()。
现在它对我来说更清楚,可能是导致前提条件失败的附加断言。已处理的函数契约如下,其中的注释表明每个断言的状态:
/*@ 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
*/
-wp-rfe标志添加的内联断言是:
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;
}
答案 0 :(得分:1)
1)这种先决条件有什么问题?
您正在使用&&
和==>
,就好像他们的相对优先权众所周知一样。从人的角度来看这是错误的,因为==>
没有出现在ACSL以外的许多语言中,只有ACSL专家可以知道依赖于其优先级的公式是什么。
除此之外,在不涉及对函数的调用的代码片段中,前提条件永远不会有任何错误。前提条件不是关于函数的实现而是关于使用函数的上下文证明的属性。您可能犯了一个错误并编写了\false
的逻辑等价物,并且前置条件对于您的代码段仍然没问题(这只会意味着对该函数的所有调用都是无效的,并且必须证明它们本身无法访问)。
为了使你的问题有意义,它必须要么:
f_mount_temp
后置条件的证明(或缺乏证明)并提供此函数的实现,或f_mount_temp
的前提条件的证明(或缺乏证明)以及调用f_mount_temp
的函数的代码,包括该函数的前置条件,因此它是可以判断这个调用函数是否尊重f_mount_temp
的先决条件。在后一种情况下,除非在调用者中多次调用,否则不必提供f_mount_temp
的代码或后置条件。此外,不需要提供从调用者调用的其他函数的代码,但是他们的契约应该是。你在这里做了什么,提供f
的代码,并询问为什么f
的前提条件未得到证实,并不是连贯的。
2)根据.Why文件中的输出,我的方法应该是找出什么错误?
这不是一个不好的地方,如果你再次提出正确的信息,我认为你可以得到帮助。
3)有人可以指点资源来学习如何调试我的函数合约吗?
我不知道其中很多,但是如果你再问一次,这个网站可以成为解释最常见调试技巧的资源......