我想切片以下程序:
int main() {
int j;
if (j) {
ERROR:
/*@ slice pragma ctrl; */
goto ERROR;
}
return 0;
}
目前,Frama-C在阅读j
后停止探索路径,导致ERROR
标签被切掉:
$ frama-c test.c -slice-pragma main -then-on 'Slicing export' -print
[...]
test.c:3:[kernel] warning: accessing uninitialized left-value: assert \initialized(&j);
test.c:3:[kernel] warning: completely indeterminate value in j.
[...]
有没有办法将阅读j
视为读取未指定的值?
我更愿意以编程方式(在Frama-C内部)执行此操作,而无需修改分析的源代码。
我正在运行Frama-C Neon。
答案 0 :(得分:1)
在执行C程序期间读取未初始化(不确定)的内存是未定义的行为or might as well be treated as such。 C程序的切片器不需要保留执行导致未定义的行为。因此,由于程序的所有执行都会导致未定义的行为,因此几乎Frama-C的切片插件生成的任何切片都是正确的切片。如果你写了if (1 / 0) {
,你可能会获得相同的行为。由于我链接到的博客文章中给出的原因,两者之间没有那么大的区别。
作为解决方案,只需使用j
内置的Frama_C_interval()
初始化__fc_builtin.h
,其中的规范在文件#include <__fc_builtin.h>
...
int j = Frama_C_interval(0, 1);
中提供:
j
如果这对您来说更简单,举个简短示例,您可以将volatile int u;
int main() {
int j = u;
...
设置为未知值,如下所示:
Frama_C_make_unknown(&x, sizeof x);
修改强>
在与托马斯私下讨论之后,我添加了以下建议:
您可以编写一个Frama-C插件,将C程序转换为等效的C程序,其中每个局部变量都被初始化。我建议使用语句进行其他初始化:
Frama_C_make_unknown
其中extern int Frama_C_entropy_source;
/*@ requires \valid(p + (0 .. l-1));
assigns p[0 .. l-1] \from Frama_C_entropy_source;
assigns Frama_C_entropy_source \from Frama_C_entropy_source;
ensures \initialized(p + (0 .. l-1));
*/
void Frama_C_make_unknown(char *p, size_t l);
是一个函数,你可以设法在原始源代码中包含规范的原型(因此必须避免添加它的困难:)
{{1}}
经过这样的转换后,切片插件可以按预期工作。如果你在制作这样一个变形插件时遇到困难,你可以在frama-c-discuss或StackOverflow中提出相关问题(后者更好,因为Google没有以任何有用的方式对frama-c-discuss进行索引)。