我开始学习 Ada 是因为它在安全至关重要的嵌入式设备中的潜在用途。到目前为止,我真的很喜欢它。然而,在我对嵌入式编程的研究中,我遇到了一个热门话题:是否在嵌入式系统中使用异常处理。我想我理解为什么有些人似乎回避它:
- 根据其实现,它可能会引入运行时开销或更大的代码大小 ( mentioned here under "Implementation" )
- 执行异常所需的时间可能是不确定的 ( one of several sources I saw )
现在我的问题是,Ada 语言或 GNAT 编译器是否解决了这些问题?我对安全关键代码的理解是,不确定的代码大小和执行时间通常是 Not Acceptable 。
尽职调查:我在确定 Ada 异常的确定性方面遇到了一些麻烦,但我的理解是它们的原始实现需要更多的运行时开销以换取减少代码大小的影响(上面的第一个链接提到了 Ada明确)。除了上面的第一个链接之外,我还研究了提到代码确定性的配置文件,例如 Ravenscar 配置文件和 this paper ,但似乎没有提到异常处理决定论。公平地说,我可能找错了地方,因为这个话题似乎很深。
最佳答案
有些嵌入式系统是安全或任务关键型的,有些是硬实时的嵌入式系统,有些是两者兼而有之的嵌入式系统。
硬实时的嵌入式系统可能会受到限制,也可能不会受到限制。同事们在 70 年代开发了一种导弹制导系统,该系统的主循环中有大约 4 个指令的净空! (正如您可以想象的,它是用汇编程序编写的,并使用经过调整的执行程序,而不是 RTOS。不支持异常)。另一方面,我在 1 GHz PowerPC 板上开发的最后一个项目,对特定中断的响应有 2 毫秒的最后期限,而我们测得的最坏情况是 1.3 毫秒(无论如何,这是一个软实时要求) ,您不必连续错过太多)。
该系统也有安全要求(我知道,我知道,安全导弹系统,呵呵),尽管我们被允许使用异常,但未处理的异常意味着系统必须关闭,无论导弹是否在飞行,导致导弹损失。而且我们被严格禁止说 when others => null;
来吞下异常,因此我们没有处理的任何异常都将是“未处理的”,并且会反弹到顶层。
争论的焦点是,如果发生未处理的异常,您将无法再知道系统的状态,因此您无法证明继续下去是合理的。当然,更广泛的安全工程必须考虑整个系统应该采取什么行动(例如,也许这个处理器应该以恢复模式重新启动)。
有时人们使用异常作为控制流程的一部分;事实上,为了处理随机文本输入,常用的方法是,不检查文件结尾,而是继续执行,直到收到 End_Error
;
loop
begin
-- read input
-- process input
exception
when End_Error => exit;
end;
end loop;
Jacob's answer讨论使用 SPARK。您不必使用 SPARK 来不处理异常,当然,如果能够向您自己(和您的安全审核员!)证明不会有任何异常,那就太好了。处理异常非常棘手,而某些 RTS(例如 Cortex GNAT RTS )则不然;配置编译指示
pragma Restrictions (No_Exception_Propagation);
意味着异常不能传播到引发异常的范围之外(程序将因调用 Last_Chance_Handler
而崩溃)。
仅在引发异常的范围内传播异常,在我看来,没有什么用处:
begin
-- do something
if some error condition then
raise Err;
end if;
-- do more
exception
when Err =>
null;
end;
将是避免“做更多”代码的相当困惑的方法。最好使用标签!
关于exception - 安全关键型嵌入式系统中的 Ada 异常(exception)情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52138488/