我开始学习Ada在嵌入式设备中的潜在用途,这对安全至关重要。到目前为止,我真的很喜欢。但是,在我对嵌入式编程的研究中,我遇到了一个热门话题,即是否在嵌入式系统中使用异常处理。我想我理解为什么有些人似乎避免这样做:
现在我的问题是, Ada语言或GNAT编译器是否解决了这些问题?我对安全性至关重要的代码的理解是不确定的代码大小和执行时间通常是不可接受的。
尽职调查:我很难确切地确定确定性Ada异常的程度,但是我的理解是它们的原始实现要求更多的运行时开销,以换取减小的代码大小影响(以上第一条链接提到Ada明确地)。除了上述第一个链接之外,我还研究了提及代码确定性的配置文件,例如Ravenscar概要文件和this paper,但似乎没有提及异常处理确定性。公平地说,由于这个话题看起来很深,所以我可能在错误的地方找东西。
答案 0 :(得分:7)
有对安全性或任务至关重要的嵌入式系统,实时性很强的嵌入式系统以及两者兼有的嵌入式系统。
实时性强的嵌入式系统可能受到约束或不受约束。同事们在20世纪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
而崩溃)。
仅在引发异常的范围内传播异常,IMO没那么有用:
begin
-- do something
if some error condition then
raise Err;
end if;
-- do more
exception
when Err =>
null;
end;
将是避免“执行更多操作”代码的一种相当混乱的方法。最好使用标签!
答案 1 :(得分:5)
异常在Ada中是确定性的。 (但是某些可以引发异常的检查具有一定的自由度。如果编译器可以提供正确的答案,则如果中间结果超出了所讨论的类型的范围,则不一定总是引发异常。)>
至少一个Ada编译器(GNAT)具有“零成本”异常实现。这并不能使异常完全免费,但是在实际引发异常之前,您无需支付运行时间成本。您仍然需要支付代码空间方面的费用。花费多少取决于架构。
我自己还没有从事安全关键系统的工作,但是我可以肯定地知道Ariane 4惯性导航系统中用于软件的运行时包含异常。
如果您不希望出现异常,则一种选择是使用SPARK(一种源自Ada的语言)。您仍然可以使用任何喜欢的Ada编译器,但是您使用SPARK工具来证明该程序不会引发任何异常。您应该注意,SPARK不是魔术。您必须通过插入断言来帮助这些工具,这些断言可以用作工具的中间步骤。