JML 在调用函数后删除警告
JML remove warning after calling a function
我接到了一项任务,我必须删除 JML 发出的所有警告。
如果我在构造函数中调用一个方法,我的 requires
和 ensures
将不再被验证,尽管为被调用的函数添加了相同的约束。
我被要求仅使用 requires
、ensures
、invariant
和 loop_invariant
.
这是代码:
/*@ non_null @*/ int[] elements;
int n;
//@ invariant n >= 0;
//@ requires input != null;
//@ requires input.length >= 0;
//@ ensures elements != null;
Class(int[] input) {
n = input.length;
elements = new int[n];
arraycopy(input, 0, elements, 0, n);
//@ assert n >= 0;
}
//@ requires srcOff >= 0;
//@ requires destOff >= 0;
//@ requires length >= 0;
//@ requires dest.length >= destOff + length;
//@ requires src.length >= srcOff + length;
//@ ensures dest.length == \old(dest.length);
//@ ensures length == \old(length) ==> length >= 0;
//@ ensures dest != null;
private static void arraycopy(/*@ non_null @*/ int[] src,
int srcOff,
/*@ non_null @*/ int[] dest,
int destOff,
int length) {
//@ loop_invariant destOff+i >= 0;
//@ loop_invariant srcOff+i >= 0;
//@ loop_invariant length >= 0;
for(int i=0 ; i<length; i=i+1) {
dest[destOff+i] = src[srcOff+i];
}
}
产生的输出:
Class.java:25: warning: The prover cannot establish an assertion (NullField) in method Class
/*@ non_null @*/ int[] elements;
^
Class.java:32: warning: The prover cannot establish an assertion (InvariantExit: MultiSet.java:27: ) in method Class
Class(int[] input) {
^
Class.java:27: warning: Associated declaration: Class.java:32:
//@ invariant n >= 0;
^
3 warnings
一个解决方案是使函数 arraycopy
成为非静态的,但我不明白为什么。
证明者无法确定 class 变量是否发生变化,因为该函数对 n
和 elements
具有可见性。因此它应该需要像
这样的注释
//@ ensures n == \old(n)
//@ ensures elements == \old(elements)
这个问题有两个不同的原因:
- 在Java中,静态方法无法访问非静态变量的值,因此JML无法证明以下规范(显示工具限制)。
// ...
//@ ensures n == \old(n)
//@ ensures elements == \old(elements)
private static void arraycopy( /* ... */ ) {
- 第二个
ensures
可能会导致一些问题,将 elements
作为 src
参数 arraycopy
。
为了避免修改函数签名,您需要在每次 arraycopy
函数调用后添加 assume
规范。
我接到了一项任务,我必须删除 JML 发出的所有警告。
如果我在构造函数中调用一个方法,我的 requires
和 ensures
将不再被验证,尽管为被调用的函数添加了相同的约束。
我被要求仅使用 requires
、ensures
、invariant
和 loop_invariant
.
这是代码:
/*@ non_null @*/ int[] elements;
int n;
//@ invariant n >= 0;
//@ requires input != null;
//@ requires input.length >= 0;
//@ ensures elements != null;
Class(int[] input) {
n = input.length;
elements = new int[n];
arraycopy(input, 0, elements, 0, n);
//@ assert n >= 0;
}
//@ requires srcOff >= 0;
//@ requires destOff >= 0;
//@ requires length >= 0;
//@ requires dest.length >= destOff + length;
//@ requires src.length >= srcOff + length;
//@ ensures dest.length == \old(dest.length);
//@ ensures length == \old(length) ==> length >= 0;
//@ ensures dest != null;
private static void arraycopy(/*@ non_null @*/ int[] src,
int srcOff,
/*@ non_null @*/ int[] dest,
int destOff,
int length) {
//@ loop_invariant destOff+i >= 0;
//@ loop_invariant srcOff+i >= 0;
//@ loop_invariant length >= 0;
for(int i=0 ; i<length; i=i+1) {
dest[destOff+i] = src[srcOff+i];
}
}
产生的输出:
Class.java:25: warning: The prover cannot establish an assertion (NullField) in method Class
/*@ non_null @*/ int[] elements;
^
Class.java:32: warning: The prover cannot establish an assertion (InvariantExit: MultiSet.java:27: ) in method Class
Class(int[] input) {
^
Class.java:27: warning: Associated declaration: Class.java:32:
//@ invariant n >= 0;
^
3 warnings
一个解决方案是使函数 arraycopy
成为非静态的,但我不明白为什么。
证明者无法确定 class 变量是否发生变化,因为该函数对 n
和 elements
具有可见性。因此它应该需要像
//@ ensures n == \old(n)
//@ ensures elements == \old(elements)
这个问题有两个不同的原因:
- 在Java中,静态方法无法访问非静态变量的值,因此JML无法证明以下规范(显示工具限制)。
// ...
//@ ensures n == \old(n)
//@ ensures elements == \old(elements)
private static void arraycopy( /* ... */ ) {
- 第二个
ensures
可能会导致一些问题,将elements
作为src
参数arraycopy
。
为了避免修改函数签名,您需要在每次 arraycopy
函数调用后添加 assume
规范。