我们一直在使用Frama-C在一个商业项目上进行“实验”静态分析(集成到我们的CI中,并在整个代码库的一小部分中进行了“少量”的选择性拦截检查)
出现的障碍之一与满足wp
插件在遇到memcpy
调用时生成的证明义务有关。具体来说,以下三项义务:
从“目标”说明中看来,Frama-C试图证明目标内存和源内存有效。
我尝试添加requires \valid()
前提条件,但这似乎无济于事。在这些情况下,被测函数中的memcpy
调用是将数据从输入参数复制到函数中,并将该数据放入局部变量中(作用域内)。
更复杂的是,要复制数据的局部变量是打包结构中的一个属性。
我确实希望人们能够分享一些memcpy
用法的真实示例,这些示例可以满足wp
引入的目标(例如,我必须添加哪些先决条件才能实现该目标可证明的?)
如果有关系,我正在运行Frama-C Magnesium-20151002(根据Ubuntu 16上的apt-get,这是“最新的”),并使用以下参数进行调用:
frama-c -wp -wp-split -wp-dynamic -lib-entry -wp-proof alt-ergo -wp-report
也相关,但缺少一个清晰的示例:Frama-c : Trouble understanding WP memory models
答案 0 :(得分:4)
正如您在评论中提到的那样,正确的解决方案是使用-wp-model "Typed+Cast"
,以使WP接受往来于void*
的强制转换(更确切地说,它将考虑p
和(void*)p
对于任何指针都是相同的,足以证明requires
的{{1}})。现在,如您所链接的问题的the answer中所述,此内存模型的主要问题(以及它不是默认值的原因)是它本质上不安全:根据假设,WP本身无法评估。这是一个突出此问题的小示例:
memcpy
基本上,默认的int x;
char* c;
/*@ assigns c;
ensures c == ((char *)&x);
*/
void g(void) {
c = &x;
}
/*@ assigns \nothing;
ensures \separated(&x,c);
*/
void f() {
}
void main () {
g();
f();
//@ assert \false;
}
内存模型可确保Typed
和c
所指向的位置(即x
的后置条件)之间的分隔,因为{ {1}}和f
不同,您既不能证明int
的后置条件,也不能将其用作在char
中推导g
的假设,因为完全无法在模型中表达平等。
现在,如果您使用\false
,则现在可以正确理解main
的后置条件,并且证明起来很简单。 WP不会让您同时证明Typed+Cast
和g
是分开的,因为它们是一起分配的。但是,在&x
中不存在这样的赋值,并且后置条件也很容易得到证明,因为我们有关于c
和f
的两个矛盾陈述,因此证明了\false
中的main
&x
。更一般而言,WP依赖于本地别名分析来跟踪不同类型的指针之间的潜在别名(全局分析会破坏使用模块化分析器的目的)。因此,将传递选项c
视为告诉WP“信任我,该程序将不会创建缺少类型的别名”。但是,可以手动传递别名信息(或在尚未编写的全局别名检测插件的帮助下)传递别名信息。例如,使用选项-wp-model +Cast
,-wp-alias-vars x,c
的后置条件变为f
(即Unknown
和&x
之间的分隔不再是假设,即使对于c
。