Ada SPARK整数溢出检查

Ada SPARK整数溢出检查,ada,ada2012,spark-2014,Ada,Ada2012,Spark 2014,我有以下计划: 火花点火模式下的主程序为 F:整数的数组(0..10):=(0,1,其他=>0); 开始 因为我在2。。最后一圈 F(I):=F(I-1)+F(I-2); 端环; 端干管; 如果运行gnatprove,我会得到以下结果,指向+符号: 中等:溢出检查可能失败 这是否意味着F(I-1)可以等于Integer'Last,向其添加任何内容都会溢出?如果是这样的话,那么从程序流程中是否不清楚这是不可能的?或者我需要在合同中说明这一点?如果不是,那是什么意思 一个反例显示,在本例中,gn

我有以下计划:

火花点火模式下的主程序为 F:整数的数组(0..10):=(0,1,其他=>0); 开始 因为我在2。。最后一圈 F(I):=F(I-1)+F(I-2); 端环; 端干管; 如果运行
gnatprove
,我会得到以下结果,指向
+
符号:

中等:溢出检查可能失败

这是否意味着
F(I-1)
可以等于
Integer'Last
,向其添加任何内容都会溢出?如果是这样的话,那么从程序流程中是否不清楚这是不可能的?或者我需要在合同中说明这一点?如果不是,那是什么意思


一个反例显示,在本例中,
gnatprove
确实担心
整数的边:

中等:溢出检查可能失败(例如,当
F=(1=>-1,其他=>-2147483648)
I=2
时)


考虑在代码中添加循环不变量。以下是“使用Spark构建高完整性应用程序”一书中的一个示例

过程复制到(缓冲区:输出缓冲区类型;
来源:在字符串中)是
字符到副本:Buffer.Count类型:=最大缓冲区大小;
开始
缓冲区:=(其他=>'');--初始化为所有空格
如果源长度<字符数,则复制
字符到副本:=源的长度;
如果结束;
对于Buffer.Count类型范围为1..Characters\u To\u复制循环中的索引
pragma循环不变量

(字符到拷贝这个循环不变量应该可以工作-因为2^(n-1)+2^(n-2)<2^n-但是我不能说服证明者:

使用SPARK_模式的Fibonacci过程是
F:Natural:=(0=>0)的数组(0..10),
1      => 1,
其他=>0);
开始
对于2..F'最后一个循环中的I
pragma循环不变量
(对于F'范围内的所有J=>F(J)<2**J);
F(I):=F(I-1)+F(I-2);
端环;
结束斐波那契;

您可能可以通过一些手动帮助说服验证人(显示2^(n-1)+2^(n-2)=2^(n-2)*(2+1)=3/4*2^n<2^n)。

这已经是一个老问题,但我还是想添加一个答案(仅供将来参考)

随着校准仪的进步,问题中所述的示例现已在GNAT CE 2019中得到验证(即不需要回路不变量)。还可以证明更先进的示例:

main.adb

火花点火模式下的主程序为 --注:N的理论上限为46,如下所示: -- --Fib(46)<2**31-1(2..46中的N), Post=>(斐波那契结果(0)=0) 然后(斐波那契结果(1)=1) 然后(对于2中的所有I..N=> 斐波那契结果(I)=斐波那契结果(I-1)+斐波那契结果(I-2)); --------------- --斐波那契-- --------------- 函数斐波那契(N:自然)返回序列为 F:Seq(0..N):=(0,1,其他=>0); 开始 对于2..N循环中的I F(I):=F(I-1)+F(I-2); pragma循环不变量 (对于2..I=> F(J)=F(J-1)+F(J-2)); --注意:下面的循环不变量有助于验证者证明 --没有溢出。它“提醒”验证程序所有值 --从迭代3开始,严格单调递增。 --因此,如果在该迭代中证明没有溢出, --然后,对于之前的所有迭代,都证明了缺席。 pragma循环不变量 (对于3中的所有J..I=> F(J)>F(J-1)); 端环; 返回F; 结束斐波那契; 开始 无效的 端干管;
我不知道如何使用
Loop\u Invariant
来实现这一点。你能举个例子吗?每次循环,你都会更改
F
的内容。你必须帮助工具,但通过再次循环告诉他们一些关于
F
的不变内容。(更新版本的SPARK工具可以被告知展开短循环,从而避免考虑循环不变量。)@jacobsparrenadersen,嗯,我认为唯一改变的是
F(I)的值
,其他一切都保持不变。不过,我不确定我能在循环不变量中表达什么来帮助工具。有人能声称
F(I)@jacobsparrenadersen,我认为只要
I ah,这是正确的。是的。我不记得这个序列的收敛极限,但我确信可以在某个地方找到它。诀窍是让你的证明者相信它是正确的。简单的解决方法是让
gnatprove
在将循环传递给provers.@Jacobsparrenadersen,我该怎么做?另外,如果
F
的上限来自用户输入,而不是常量
10
,这难道不是一个问题吗?我认为循环展开是由某个命令行参数控制的。不,如果范围是动态的,循环展开将不起作用。那么你必须知道你的数学怎么样。