Frama-C提示缺失assigns子句(默认assigns 'everything')问题咨询
解决Frama-C WP插件的两个常见警告:Missing RTE Guards和Missing Assigns Clause
我来帮你拆解这两个警告,以及你困惑的assigns 'everything'到底是什么意思:
1. 第一个警告:Missing RTE guards
这个提示来自Frama-C的WP(Weakest Precondition)插件,意思是你的代码缺少运行时错误(Run-Time Error,RTE)的防护注解。
具体到你的代码:循环里的i += 2操作,WP默认会检查整数溢出的可能性——哪怕你假设n是非负偶数,但如果n大到让i加2后超出int类型的取值范围,就会触发溢出错误。插件提醒你要么显式排除这种风险,要么添加防护条件。
解决办法:可以在函数的requires注解里加上n <= INT_MAX(记得先包含头文件#include <limits.h>),明确限制n的最大值不会导致溢出。
2. 第二个警告:Missing assigns clause(对应你提到的assigns 'everything')
这是WP插件的核心要求之一:它需要明确知道你的函数会修改哪些内存位置。如果你完全没写assigns注解,WP会默认这个函数可以修改'everything'——也就是所有内存区域(包括全局变量、堆内存、其他局部变量等)。
这种默认行为会让验证变得非常宽泛,不仅降低效率,还可能导致验证结果不准确。而你的函数f里,唯一被修改的只有局部变量i,所以必须显式告诉WP这一点。
解决办法:在函数的ACSL注解里添加assigns i;,明确声明这个函数只会修改局部变量i,不会触碰其他任何内存。
修改后的完整可验证代码
#include <limits.h> // 假设n为非负偶数,f返回n /*@ requires n >= 0; requires n <= INT_MAX; // 防止i += 2时发生整数溢出 assigns i; // 明确函数仅修改局部变量i ensures \result == n; // 用ensures替代单独的assert,更符合ACSL规范 */ int f(int n) { int i = 0; while (i < n) { /*@ loop invariant i >= 0; loop invariant i <= n; loop invariant i % 2 == 0; // 每次加2,i始终是偶数,匹配n为偶数的假设 loop variant n - i; // 循环变体:证明循环一定会终止(值不断减小至0) */ i += 2; } //@ assert i == n; return i; }
额外补充
- 添加
loop invariant和loop variant是帮WP更好地验证循环的正确性:loop variant用来证明循环必然终止,loop invariant描述循环过程中始终成立的属性。 - 如果你的函数涉及全局变量或指针,
assigns里要列出所有被修改的对象,比如assigns global_counter, *ptr, i;。 - 为什么
assigns 'everything'不好?因为WP会假设函数可能修改任何内存,这会让它在验证后置条件时,不得不考虑所有可能的内存修改对结果的影响,很可能导致验证失败,或者需要更多不必要的注解来排除干扰。
内容的提问来源于stack exchange,提问作者the_martian
相关产品推荐
相关产品推荐

