frama-c停止传播:“;断言获取的状态无效";

frama-c停止传播:“;断言获取的状态无效";,c,frama-c,program-slicing,C,Frama C,Program Slicing,我想为所有断言分割文件test.c test.c如下所示: #包括 类型定义结构{ 浮子r; 浮球g; 浮球b; }色彩; 类型定义结构{ int k; 颜色*颜色; }色彩; void foo(int*a、int*k、Colors*Colors) { int b=0; 颜色->颜色=(颜色*)malloc(k*sizeof(颜色)); //@断言(colors==NULL); 如果(颜色==NULL) 返回; 颜色->k=k; int c=10; *a=8; //@断言(*a>b); } 我

我想为所有断言分割文件
test.c

test.c
如下所示:

#包括
类型定义结构{
浮子r;
浮球g;
浮球b;
}色彩;
类型定义结构{
int k;
颜色*颜色;
}色彩;
void foo(int*a、int*k、Colors*Colors)
{
int b=0;
颜色->颜色=(颜色*)malloc(k*sizeof(颜色));
//@断言(colors==NULL);
如果(颜色==NULL)
返回;
颜色->k=k;
int c=10;
*a=8;
//@断言(*a>b);
}
我使用以下命令运行frama-c:

frama-c-slice assert@all-main foo test.c-然后在“切片导出”上打印-ocode slice.c

生成的
slice.c
如下所示:

/*由Frama-C生成*/
typedef unsigned int size\u t;
结构颜色1{
浮子r;
浮球g;
浮球b;
};
typedef struct\uu anonstruct\u Color\u1 Color;
结构颜色2{
int k;
颜色*颜色;
};
typedef struct\uuu anonstruct\u Colors\u2 Colors;
/*@ghost extern int uuu fc u heap uu status uuu属性uuu((uuu FRAMA_C_MODEL_uu))*/
/*@
公理化动态分配{
谓词是可分配的{L}(size\t n)
读取_fc_heap_状态;
}
*/
void foo(int*a,Colors*Colors)
{
int b;
/*@断言颜色≡ (颜色*)((空白*)0);*/;
返回;
}
查看切片函数
foo
,处理过程似乎不完整。frama-c输出告诉我:

test.c:19:[kernel] warning: out of bounds write. assert \valid(&colors->colors);
test.c:20:[value] Assertion got status invalid (stopping propagation).

“状态无效”应该是什么意思?当我将第一个断言更改为
/@assert(colors!=NULL)时,为什么它在这里停止传播,为什么它可以工作

切片插件依赖于通过值分析计算的信息。在运行过程中,值分析尝试评估它所探索的分支上存在的任何ACSL注释。这尤其适用于
assert colors==NULL在您的示例中,它确实被认为是无效的

为什么呢?首先,我们可以注意到,
colors
是主入口点的形式参数。默认情况下,值分析将创建一个初始状态,其中该指针为
NULL
或指向两个元素块的指针(有关分析的默认初始状态以及如何在需要时对其进行自定义的更多信息,请参阅)。因此,断言似乎只是删除了第二种可能性,并将
NULL
作为
颜色的唯一可能性

但是,在到达
断言
之前,函数对
颜色
做的另一件事是:它在
颜色->颜色
中赋值。要使此分配有效,
colors
需要指向有效的内存位置。因此,您在第19行看到的警告(看起来是内核出于历史原因发出的,但实际上是由值发出的),通过生成另一个断言
\valid(&colors->colors)
具体化,您可以看到,如果您使用您的选项启动
frama-c-gui

发出警报后,Value尝试根据它来降低其内部状态,因为如果它验证给定的条件,则具体执行只能进一步(不冒险进入未定义的行为区域)。在我们的例子中,这意味着删除
colors
的一组可能值的
NULL
。因此,当我们遇到断言时,我们只有一种可能性使用
颜色
,因为它与断言不匹配,所以状态无效,传播停止:没有具体的执行可以达到这一点并验证断言

如果将第一个断言更改为
/@assert(colors!=NULL),则更新,值分析将发现它是有效的,因为如上所述,由于上一条指令中的
colors->colors
,因此到达断言的评估点只能使用有效的
colors
指针。因此,值继续进行分析,并在正常终止的程序上执行切片,从而得到预期的结果

关于您的注释,如果在通过注释的程序的任何具体执行期间,ACSL注释的计算结果为true,则ACSL注释是有效的,否则无效(如果注释的计算结果为false,则执行应该停止)。在实践中,通常不可能(至少在合理的时间和/或内存内)执行所有此类评估,因此状态未知,这意味着插件无法决定。请注意,在任何情况下,给定插件发出的状态取决于该插件的配置。例如,对于Value,选择的入口点和初始配置对Value在抽象执行期间遇到的注释的有效性状态有影响。更准确地说,每次抽象执行到达注释时,状态计算如下:

  • 如果注释对于当前抽象状态表示的所有具体状态都为true,则会发出有效状态
  • 如果所有这些具体状态的注释都为false,则发出invalid status,并停止该分支的抽象执行(因为没有任何具体执行会经过注释)

  • 否则,状态是未知的:Value无法知道注释计算为false的具体状态在实践中是否真的会发生,或者只是迄今为止所做近似的人工制品。但是,它试图减少其抽象状态,使其表示尽可能少的无效状态(例如,如果您有
    /*@assert 0它是一个拼写错误,我的意思是
    /@assert(colors!=NULL);
    (编辑我的问题)显然,我认为我有点误解了ACSL断言的含义……因为我不认为我100%地理解了这一点,你能给“地位”下个定义吗