我试图在C中证明像strlen这样的函数,但是frama-c并不能证明
发布条件和loop variant len
子句。我无法理解为什么!
我尝试过的事情:
/*@
axiomatic elementNumber_axioms
{
logic unsigned elementNumber{L}(char *a);
axiom elementNumber_base{L}:
elementNumber(\null) == 0;
axiom elementNumber_step{L}:
\forall char *a;
\valid(a) ==> elementNumber(a) == elementNumber(a+1) + 1;
}
*/
/*@
assigns \nothing;
ensures \result == elementNumber(\old(s));
*/
unsigned stringlen(const char *s)
{
unsigned len = 0;
/*@
loop assigns len;
loop assigns s;
loop variant len;
*/
while(*s)
{
++s;
++len;
}
return len;
}
我做错了什么?
答案 0 :(得分:3)
你写的内容有几个问题。一份非详尽的清单:
你的stringlen()不处理s
为NULL的情况。
如果注释标准的C strlen()函数,则不需要处理这种情况,因为标准的C strlen()函数不允许参数为NULL
。但是,elementNumber()逻辑函数的公理定义将elementNumber(\null)
定义为0,而stringlen()的后置条件是结果等于elementNumber(s)
。因此,您需要处理此案例。
stringlen()中的while循环在遇到nul字节时终止。但是,elementNumber()逻辑函数的定义仅取决于指针是否有效。
stringlen()没有关于s
,s + 1
等是否有效的先决条件。
您的elementNumber()逻辑函数未定义无效指针的值。
您需要指定循环不变量。
我建议看看Frama-C如何注释strlen():
/*@ requires valid_string_src: valid_string(s);
@ assigns \result \from s[0..];
@ ensures \result == strlen(s);
@*/
extern size_t strlen (const char *s);
strlen()逻辑函数和valid_string()谓词在源代码分发的share/libc/__fc_string_axiomatic.h
中定义,在撰写本文时为Sodium-20150201。