frama-c 切片插件似乎丢弃使用过的堆栈值
frama-c slicing plugin appears to discard used stack values
问题描述
我正在开发一个 frama-c 插件,它使用切片插件作为库来删除未使用的自动生成代码位。不幸的是,切片插件会丢弃一堆实际使用的堆栈值。只要它们的地址包含在传递给抽象外部函数的结构中,它们就会被使用。
简单示例
这是一个更简单的示例,它模拟了我所拥有的相同的一般结构。
/* 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[]);
然后我尝试使用确实具有所需行为的分配(见下文)。然而,这不是一个正确的规范,因为该函数实际上从未写入指针,而是需要读取它才能实现正确的功能。我担心如果我继续使用这样一个不正确的规范,它会导致奇怪的问题。
/*@ requires \valid(ints) && \valid(ints[0]);
assigns *ints;
*/
void some_function(int* ints[]);
您在正确的轨道上:您应该在此处使用 assigns
子句:它将指示内存状态的哪些部分与未定义函数的调用有关。但是,您需要提供一个完整的 assigns
子句,其 \from
部分(指示读取哪个内存位置以计算写入的内存位置的新值)。
我在您的示例中添加了一个 int
变量,因为您的函数没有 return 结果(void
return 类型)。对于一个 returning 东西的函数,你还应该有一个子句 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
标签表明我们没有直接使用它们的值,这在 Eva's manual 的第 8.2 节中有更详细的描述),以及它们的内容。
using 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*
大批。但我认为它只是源于减少你原来的例子,对切片本身并不重要。
问题描述
我正在开发一个 frama-c 插件,它使用切片插件作为库来删除未使用的自动生成代码位。不幸的是,切片插件会丢弃一堆实际使用的堆栈值。只要它们的地址包含在传递给抽象外部函数的结构中,它们就会被使用。
简单示例
这是一个更简单的示例,它模拟了我所拥有的相同的一般结构。
/* 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[]);
然后我尝试使用确实具有所需行为的分配(见下文)。然而,这不是一个正确的规范,因为该函数实际上从未写入指针,而是需要读取它才能实现正确的功能。我担心如果我继续使用这样一个不正确的规范,它会导致奇怪的问题。
/*@ requires \valid(ints) && \valid(ints[0]);
assigns *ints;
*/
void some_function(int* ints[]);
您在正确的轨道上:您应该在此处使用 assigns
子句:它将指示内存状态的哪些部分与未定义函数的调用有关。但是,您需要提供一个完整的 assigns
子句,其 \from
部分(指示读取哪个内存位置以计算写入的内存位置的新值)。
我在您的示例中添加了一个 int
变量,因为您的函数没有 return 结果(void
return 类型)。对于一个 returning 东西的函数,你还应该有一个子句 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
标签表明我们没有直接使用它们的值,这在 Eva's manual 的第 8.2 节中有更详细的描述),以及它们的内容。
using 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*
大批。但我认为它只是源于减少你原来的例子,对切片本身并不重要。