我正在开发一个frama-c插件,使用slicing插件作为库来删除自动生成的代码中未使用的部分。不幸的是,slicing插件丢弃了一堆堆栈值,而这些堆栈值实际上是被使用的。它们被使用的原因是它们的地址包含在结构中,而这些结构被交给了抽象的外部函数。
这是一个更简单的例子,它的模型与我的一般结构相同。
/* Abstract external function */
void some_function(int* ints[]);
int main() {
int i;
int *p = &i;
int *a[] = { &p };
some_function(a);
return 0;
}
当用 frama-c-gui -slice-calls some_function experiment_slicing.c
(我还不知道如何在没有gui的情况下调用命令行时看到切片输出)除了声明之外,它放弃了所有的东西。int *a[];
和呼吁 some_function
.
我试着通过添加ACSL注释来解决这个问题.然而我认为是合理的规范(见下文)并没有发挥作用。
/*@ requires \valid(ints) && \valid(ints[0]);
*/
void some_function(int* ints[]);
然后我尝试了一个assign(见下图),它确实具有所需的行为。然而这并不是一个正确的规范,因为函数实际上从未向指针写入,而是需要读取它以实现正确的功能。我担心如果我继续使用这样一个不正确的规范,会导致以后出现奇怪的问题。
/*@ requires \valid(ints) && \valid(ints[0]);
assigns *ints;
*/
void some_function(int* ints[]);
你的方向是对的:是这个问题。assigns
子句,你应该在这里使用:它将指出对未定义函数的调用涉及到内存状态的哪些部分。然而,您需要提供一个完整的 assigns
句,以及其 \from
部分(表示读取哪个内存位置以计算写入的内存位置的新值)。
我已经添加了一个 int
变量,因为你的函数并没有返回一个结果(void
return type).对于返回东西的函数,你也应该有一个子句。对于一个要返回东西的函数,你还应该有一个子句 assigns \result \from ...;
:
int x;
/*@ assigns x \from indirect:ints[..], *(ints[..]); */
void some_function(int* ints[]);
int main() {
int i;
int*p = &i;
int *a[] = { &p };
some_function(a);
return 0;
}
负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: assigns
子句表示 some_function
可能会改变 x
中存储的地址计算出新的值。ints[..]
(该 indirect
标签告诉我们,我们并没有直接使用它们的值,这一点将在8.2节的 Eva的手册),以及它们的内容。
使用 frama-c -slice-calls some_function file.c -then-last -print
(最后一个参数是用来在标准输出上打印结果的文件。-then-last
表示以下选项应在最后创建的Frama-C项目上操作,在这种情况下,就是切片后的项目,以及 -print
打印该工程的C代码。你也可以使用 -ocode output.c
以将代码的漂亮打印重定向至 output.c
...)给出了以下结果。
* Generated by Frama-C */
void some_function(int **ints);
void main(void)
{
int i;
int *p = & i;
int *a[1] = {(int *)(& p)};
some_function(a);
return;
}
另外,请注意你的例子没有很好的类型。&p
是一个指向int的指针, 因此应该存储在... int**
数组,而非 int*
数组。但我认为这只是源于减少你原来的例子,对于切片本身并没有太大的影响。