如何在 Frama-C 中证明整数是有限的
How to prove integers are finite in Frama-C
我有一小段 c 代码,如下所示:
double sum(double a, double b) {
return a+b; }
当我使用 eva-wp 运行 时,出现错误:
non-finite double value. assert \is_finite(\add_double(a, b));
但是当我添加时:
requires \is_finite(\add_double(a, b));
然后状态变为未知。
我觉得我犯了一个很简单的错误,但我不知道它是什么!
如果我们考虑file.c
:
/*@ requires \is_finite(\add_double(a,b)); */
double sum(double a, double b) {
return a+b;
}
并使用 frama-c -eva -main sum file.c
启动 Eva,我们确实处于未知状态,并且警报仍然存在。事实上,这是两个不同的问题。
首先,当主入口点中有一个 requires
子句时,Eva 尝试根据它计算的通用初始状态对其进行评估,其中 double
值可以是任何有限的double
(甚至无限或 NaN,取决于内核选项 -warn-special-float
的值)。在此通用状态下,requires
不成立,因此 Unknown
状态。
其次,Eva 无法利用 requires
子句将此初始状态还原为 属性 成立的抽象状态:这将需要维持某种关系a
和 b
,这不在当前 Eva 中实现的抽象域的范围内。因此,分析是使用与没有 requires
完全相同的抽象状态完成的,并导致相同的警报。
为了验证requires
(并使警报消失),您可以使用包装函数,它将构建更合适的初始状态并调用正在分析的函数,例如
#include <float.h>
#include "__fc_builtin.h"
/*@ requires \is_finite(\add_double(a,b)); */
double sum(double a, double b) {
return a+b;
}
void wrapper() {
double a = Frama_C_double_interval(-DBL_MAX/2, DBL_MAX/2);
double b = Frama_C_double_interval(-DBL_MAX/2, DBL_MAX/2);
double res = sum(a,b);
}
Frama_C_double_interval
,在 $(frama-c -print-share-path)/libc
中的 __fc_builtin.h
中声明,连同其他标量类型的类似函数,returns 作为参数给出的边界之间的随机双精度值。因此,从 Eva 的角度来看,结果在相应的区间内。通过启动 frama-c -eva -main wrapper file.c
,我们没有任何警报(并且 requires
有效)。更一般地说,此类包装器通常是构建用于使用 Eva 进行分析的初始状态的最简单方法。
我有一小段 c 代码,如下所示:
double sum(double a, double b) {
return a+b; }
当我使用 eva-wp 运行 时,出现错误:
non-finite double value. assert \is_finite(\add_double(a, b));
但是当我添加时:
requires \is_finite(\add_double(a, b));
然后状态变为未知。
我觉得我犯了一个很简单的错误,但我不知道它是什么!
如果我们考虑file.c
:
/*@ requires \is_finite(\add_double(a,b)); */
double sum(double a, double b) {
return a+b;
}
并使用 frama-c -eva -main sum file.c
启动 Eva,我们确实处于未知状态,并且警报仍然存在。事实上,这是两个不同的问题。
首先,当主入口点中有一个 requires
子句时,Eva 尝试根据它计算的通用初始状态对其进行评估,其中 double
值可以是任何有限的double
(甚至无限或 NaN,取决于内核选项 -warn-special-float
的值)。在此通用状态下,requires
不成立,因此 Unknown
状态。
其次,Eva 无法利用 requires
子句将此初始状态还原为 属性 成立的抽象状态:这将需要维持某种关系a
和 b
,这不在当前 Eva 中实现的抽象域的范围内。因此,分析是使用与没有 requires
完全相同的抽象状态完成的,并导致相同的警报。
为了验证requires
(并使警报消失),您可以使用包装函数,它将构建更合适的初始状态并调用正在分析的函数,例如
#include <float.h>
#include "__fc_builtin.h"
/*@ requires \is_finite(\add_double(a,b)); */
double sum(double a, double b) {
return a+b;
}
void wrapper() {
double a = Frama_C_double_interval(-DBL_MAX/2, DBL_MAX/2);
double b = Frama_C_double_interval(-DBL_MAX/2, DBL_MAX/2);
double res = sum(a,b);
}
Frama_C_double_interval
,在 $(frama-c -print-share-path)/libc
中的 __fc_builtin.h
中声明,连同其他标量类型的类似函数,returns 作为参数给出的边界之间的随机双精度值。因此,从 Eva 的角度来看,结果在相应的区间内。通过启动 frama-c -eva -main wrapper file.c
,我们没有任何警报(并且 requires
有效)。更一般地说,此类包装器通常是构建用于使用 Eva 进行分析的初始状态的最简单方法。