Ada 交换数组索引中的潜在别名冲突

Ada 交换数组索引中的潜在别名冲突,ada,formal-verification,formal-methods,spark-ada,Ada,Formal Verification,Formal Methods,Spark Ada,本课程包含一个示例(#5),其中GNATprove无法证明在交换数组的两个元素的过程中没有出现混叠: package P with SPARK_Mode => On is type P_Array is array (Natural range <>) of Positive; procedure Swap_Indexes (A : in out P_Array; I, J : Natural); procedure Swap (X, Y : in ou

本课程包含一个示例(#5),其中GNATprove无法证明在交换数组的两个元素的过程中没有出现混叠:

package P
  with SPARK_Mode => On
is
   type P_Array is array (Natural range <>) of Positive;

   procedure Swap_Indexes (A : in out P_Array; I, J : Natural);
   procedure Swap (X, Y : in out Positive);
end P;

package body P
  with SPARK_Mode => On
is
   procedure Swap (X, Y : in out Positive) is
      Tmp : constant Positive := X;
   begin
      X := Y;
      Y := Tmp;
   end Swap;

   procedure Swap_Indexes (A : in out P_Array; I, J : Natural) is
   begin
      Swap (A (I), A (J));
   end Swap_Indexes;

end P;
P包
火花_模式=>打开时
是
类型P_数组是正的数组(自然范围);
过程交换索引(A:输入输出P_数组;I,J:自然);
程序交换(X,Y:输入输出正);
P端;
包体P
火花_模式=>打开时
是
程序交换(X,Y:输入输出正)为
Tmp:常数正:=X;
开始
X:=Y;
Y:=Tmp;
末端互换;
过程交换索引(A:in-out P_数组;I,J:Natural)是
开始
掉期(A(I)、A(J));
结束交换索引;
P端;

GNATprove说
p.adb:13:13:medium:形式参数“X”和“Y”可能有别名(SPARK RM 6.4.2)
。这似乎是一个有效的错误,因为传递给
Swap\u索引的索引可能相等。但是,在将前提条件
Pre=>I/=J
添加到
Swap_索引
之后,GNATprove仍然无法证明缺少别名。为什么前提条件不足?

如评论中所述,可以通过从包规范中删除
交换
子程序来减轻潜在混淆的警告。但是,
交换索引
上的前提条件
I/=J
也可以省略,而不会改变结果。此外,在包规范中再次添加一个新的
Swap2(a,B:in-out-Positive)
子程序,该子程序只调用包体中现在的本地
Swap
,不会导致潜在别名警告重新出现。这表明问题实际上是调用
交换
,而不是可见性

查看GNATprove的输出(即已验证的检查信息),似乎从包规范中删除
Swap
会导致GNAT编译器(前端)将
Swap
内联到
Swap\u索引中。内联有效地从
Swap\u索引
中删除对
Swap
的调用,并以此作为警告别名可能产生的影响的理由

注意:这实际上可以通过将调试选项
-gnatd.j
传递给编译器(请参阅)并将选项
--no-inline
传递给GNATprove来验证,如下例所示

因此,对于特定示例,虽然可以通过从包规范中删除
Swap
来减轻关于别名的警告,但解决方案并没有回答为什么前提条件
I/=J
不能证明没有别名的原始问题。虽然我不能确定,但我怀疑这只是GNATprove证明非静态实际参数不存在别名的能力的当前限制。因此注意到,尽管在示例中给定了前提条件,没有混叠效果是显而易见的,但在一般情况下证明这一点可能会很快变得(非常)困难

p.ads

package P with SPARK_Mode is

   type P_Array is array (Natural range <>) of Positive;

   procedure Swap_Indexes (A : in out P_Array; I, J : Natural)
     with Pre => I in A'Range and J in A'Range;
   
   procedure Swap2 (A, B : in out Positive)
     with Global => null;
   
end P;
输出(GNATprove)

请求GNATprove not inline(
--no inlining
)会使警告重新出现,即使前提条件
I/=J
已添加到
Swap\u索引中

输出(GNATprove)


您的程序不能确保I或J在P_数组实例A的索引值范围内。例如,如果传递给正式参数A的实际参数是一个包含10个元素的数组,范围为0..9,参数I和J分别为11和23,则无法证明交换。尝试添加I和J都在“范围”内的前提条件。我尝试将前提条件
Pre=>I/=J和I在“范围”中,J在“范围”中添加到
Swap_索引中
,但GNATprove给了我关于潜在别名的相同错误消息。这是断言
I
J
A
的索引值范围内的正确方法吗?在我看来,问题在于
交换。因为它是公共的,所以可能会从pkg外部调用它,并且不能保证不会使用两个参数的相同变量调用它。如果将其从规范中删除,会发生什么?@JeffreyR.Carter这也是我的第一个想法,并且在从pkg规范中删除
Swap
后,关于潜在别名的警告确实消失了。但是,在
Swap\u索引
上的前提条件
I/=J
也可以省略,而不会改变结果。此外,在pkg规范中再次添加一个新的
Swap2(a,B:in-out-Positive)
子程序,该子程序只调用pkg主体中现在的本地
Swap
,不会导致潜在别名警告重新出现。这表明问题实际上是调用
Swap
,而不是可见性…@DeeDee对我来说,
Swap
的可见性对验证结果有影响确实很奇怪。从pkg规范中删除
Swap
后,如果我将
Swap_索引的实现更改为
Swap(A(I),A(I))
(Swap的两个参数肯定是相同的),那么GNATprove不会报告任何别名。
package body P with SPARK_Mode is
   
   procedure Swap (X, Y : in out Positive) is
      Tmp : constant Positive := X;
   begin
      X := Y;
      Y := Tmp;
   end Swap_Local;
   
   procedure Swap_Indexes (A : in out P_Array; I, J : Natural) is
   begin
      Swap (A (I), A (J));
   end Swap_Indexes;
   
   procedure Swap2 (A, B : in out Positive) is
   begin
      Swap (A, B);
   end Swap2;

end P;
$ gnatprove -Pdefault.gpr -j0 --level=1 --report=all -cargs -gnatd.j
Phase 1 of 2: generation of Global contracts ...
List of calls inlined by the frontend
  1:p.adb:12:7:
  2:p.adb:17:7:
Phase 2 of 2: flow analysis and proof ...
List of calls inlined by the frontend
  1:p.adb:12:7:
  2:p.adb:17:7:
p.adb:4:34: info: index check proved, in call inlined at p.adb:12
p.adb:6:07: info: index check proved, in call inlined at p.adb:12
p.adb:6:12: info: index check proved, in call inlined at p.adb:12
p.adb:7:07: info: index check proved, in call inlined at p.adb:12
p.ads:9:11: info: data dependencies proved
Summary logged in [...]/gnatprove.out
$ gnatprove --no-inlining -Pdefault.gpr -j0 --level=1 --report=all -cargs -gnatd.j
Phase 1 of 2: generation of Global contracts ...
Phase 2 of 2: flow analysis and proof ...
p.adb:12:13: medium: formal parameters "X" and "Y" might be aliased (SPARK RM 6.4.2)
p.adb:12:16: info: index check proved
p.adb:12:23: info: index check proved
p.ads:9:11: info: data dependencies proved
Summary logged in [...]/gnatprove.out