【问题标题】:Implicit Function Contract not available for Proof隐式函数契约不可用于证明
【发布时间】:2018-01-23 20:50:31
【问题描述】:

我在 SPARK 包中有一个过程,它从非 SPARK 包中调用一些函数。

procedure do_monitoring is
   U_C1 : constant Float := Sim.Get_U_C1;
   I_L1 : constant Float := Sim.Get_I_L1;
   U_C2 : constant Float := Sim.Get_U_C2;
   I_L2 : constant Float := Sim.Get_I_L2;
begin
   pragma Assert (U_C1 in Float_Signed1000);
   pragma Assert (I_L1 in Float_Signed1000);
   pragma Assert (U_C2 in Float_Signed1000);
   pragma Assert (I_L2 in Float_Signed1000);
   --  Monitor PFC intermediate voltage
   monitor_signal (monitor_pfc_voltage, U_C1);
   --  Monitor PFC inductor current
   monitor_signal (monitor_pfc_current, I_L1);
   --  Monitor output voltage
   monitor_signal (monitor_output_voltage, U_C2);
   --  Monitor output inductor current
   monitor_signal (monitor_output_current, I_L2);
end do_monitoring;

GNAT 为我从全局受保护类型调用函数的所有四个声明行提供了 info: implicit function contract not available for proof (<function_name> may not return)

受保护类型函数在非 SPARK 包中定义如下,并使用在受保护类型私有部分中声明的记录 Sim_Out。所有的记录值都用0.0初始化。

function Get_I_L1 return Float is
begin
   return Sim_Out.I_L1;
end Get_I_L1;

function Get_U_C1 return Float is
begin
   return Sim_Out.U_C1;
end Get_U_C1;

function Get_I_L2 return Float is
begin
   return Sim_Out.I_L2;
end Get_I_L2;

function Get_U_C2 return Float is
begin
   return Sim_Out.U_C2;
end Get_U_C2;

有什么办法可以解决这个问题?我确实已经添加了一些编译指示来为证明者提供额外的信息subtype Float_Signed1000 is Float range -1_000.0 .. 1_000.0,但这并没有达到我的预期。

我想在这里就这个话题提出你的建议。

【问题讨论】:

  • 我会跟进提示“函数可能不会返回”......我们没有 Sim_Get_* 的来源,但你有。有没有通过这些不返回的路径?
  • @BrianDrummond 等一下,我会快速编辑我的问题。
  • 我刚刚在谷歌上搜索了“隐式函数合约不可用于证明”(没有引号;有引号我才得到这个问题),第七个答案看起来很相关;在最后一节。当我添加“spark2014”时,Google 对这个命中的排名更高。
  • @SimonWright 如果您粘贴 URL 将不胜感激 :-)
  • 试试this ...

标签: ada gnat spark-ada


【解决方案1】:

如果允许我编辑 Sim 包,我可以说例如

package Sim
with SPARK_Mode
is
   function Get return Float
   with Annotate => (Gnatprove, Terminating);
end Sim;

(那是使用AdaCore的spark2017版本),后续使用非SPARK体

package body Sim is
   function Get return Float is (42.0);
end Sim;

报告显示 Sim.Get 已被跳过。

我不知道 SPARK2014 的后续版本对此有何反应,因为 User Guide 的含义是 Annotate 为证明者设定了一个目标,但我们不允许它调查Sim 的正文进行检查。

参考手册中可能还有更多内容 - 访问 adacore.com,选择 Resources/Documentation/SPARK。

【讨论】:

  • 有没有可能告诉SPARK我已经测试了函数保证它会终止?当你有一个不能处于 SPARK 模式的包时,你如何解决这样的问题,因为它使用了 SPARK 中不允许的功能,其子程序由 SPARK 包调用。 Brian Drummonds 包装器包是一个可行的替代方案吗?
  • 证明者明年如何知道这仍然是正确的?我认为你必须在某个时候证明这种事情的合理性——也许在验证报告中。例如,如果您无法更改 Sim 包,Brian 的建议会有所帮助,但在底部仍然存在不可证明性。我有一种感觉,证明者在看到 pragma Assume 时会报告,如果这也能在这里工作会很好(这样你就会知道你必须“手动”证明哪些部分是合理的)。
  • 我选择使用注释来证明消息的合理性。我在user guide 中找到了更多信息,并通过在每条标记线下方添加pragma Annotate (GNATprove, False_Positive, "may not return", "checked by Simon") 进行了尝试。但是它不起作用,可能是因为它不是错误或警告,而是信息。有什么建议吗?
  • 我在上面给7.4.6 的链接表明你需要一个不同形式的pragma Annotate 来达到这个目的(或者我在答案中显示的方面;这个注释特定于命名的子程序,而您尝试使用的是特定于代码中的位置)。
  • 谢谢,这完全有效。我在 callees 包规范中激活了 SPARK,并使用 with 关键字添加了建议的注释。在您给出答案后,我已经尝试过,但是我收到了一个关于未初始化数组的有效警告,该数组使 GNATprove 终止并且不检查其他内容。我不知道,并认为注释不起作用。 GNATprove 继续检查源代码的其余部分,然后我修复了数组初始化并且注释工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-13
  • 2021-01-20
  • 2014-06-28
  • 1970-01-01
相关资源
最近更新 更多