scanf在Frama-C中没有按预期工作

时间:2017-02-28 12:23:51

标签: static-analysis frama-c value-analysis

在下面的程序中,函数dec使用scanf来读取用户的任意输入。

Frama-C screenshot of function dec

dec调用

main并根据输入返回1或0,因此将执行操作。但是,值分析表明y始终为0,即使在调用scanf之后也是如此。那是为什么?

1 个答案:

答案 0 :(得分:2)

注意:以下评论适用于Frama-C 15之前的版本(Phosphorus,20170501);在Frama-C 15中,Variadic插件默认启用(其短名称现为-variadic)。

解决方案

  • 在运行值分析(-va)之前启用Variadic(-val),它将消除警告,程序将按预期运行。

详细说明

严格来说,Frama-C本身(内核)只进行解析;它取决于插件本身(例如Value / EVA)来评估程序。

根据您的描述,我相信您必须使用Value / EVA来分析程序。我不确切知道您使用的是哪个版本,因此我将描述Frama-C Silicon的行为。

ACSL(Frama-C使用的规范语言)的一个限制是,目前无法为scanf等可变函数指定合约。因此,Frama-C标准库附带的规格不足。您可以在以下程序中注意到这一点:

#include <stdio.h>
int d;

int main() {
  scanf("%d", &d);
  Frama_C_show_each(d);
  return 0;
}

运行frama-c -val file.c将输出以下内容:

...
[value] using specification for function scanf
FRAMAC_SHARE/libc/stdio.h:150:[value] warning: no \from part for clause 'assigns *__fc_stdin;' of function scanf
[value] Done for function scanf
[value] Called Frama_C_show_each({0})
...

该警告意味着规范不正确,这解释了奇怪的行为。

在这种情况下的解决方案是使用Variadic插件(-va-va-help获取更多详细信息),这将专门调用可变参数调用并为其添加规范,从而避免警告和表现如预期。这是在上面的示例中运行Variadic插件后生成的代码(-print):

$ frama-c -va file.c -print

[... lots of definitions from stdio.h ...]

/*@ requires valid_read_string(format);
    requires \valid(param0);
    ensures \initialized(param0);
    assigns \result, *__fc_stdin, *param0;
    assigns \result
      \from (indirect: *__fc_stdin), (indirect: *(format + (0 ..)));
    assigns *__fc_stdin
      \from (indirect: *__fc_stdin), (indirect: *(format + (0 ..)));
    assigns *param0
      \from (indirect: *__fc_stdin), (indirect: *(format + (0 ..)));
 */
int scanf_0(char const *format, int *param0);

int main(void)
{
  int __retres;
  scanf_0("%d",& d);
  Frama_C_show_each(d);
  __retres = 0;
  return __retres;
}

在此示例中,scanf专门用于scanf_0,具有适当的ACSL注释。在此程序上运行EVA不会发出任何警告并产生预期的输出:

@ frama-c -va file.c -val 

...
[value] Done for function scanf_0
[value] Called Frama_C_show_each([-2147483648..2147483647])
...

注意:Frama-C 14(Silicon)中的GUI不允许启用Variadic插件(即使在Analyses面板中勾选它后),所以必须在这种情况下使用命令行来获取预期结果并避免警告。从Frama-C 15(Phosphorus,将于2017年发布)开始,这不是必需的:默认情况下将启用Variadic,因此您的示例将从一开始就有效。