在外国功能安全的外国人世界中的编纂者

跨部门,功能安全世界对开发商提出了新的要求。功能安全代码必须包括防御代码,以防御可能由各种原因导致的意外事件。例如,由于编码错误或宇宙射线事件导致的内存损坏可能导致根据代码的逻辑执行的代码路径。高级语言,特别是C和C ++,包括令人惊讶的特征,其行为未被代码遵守的语言规范规定。这种未定义的行为可能导致意外和潜在的灾难性结果,这在功能安全的应用中是不可接受的。由于这些原因,标准要求应用防御性编码,该代码是可测试的,即可以抵消足够的代码覆盖,并且该应用程序代码可追溯到要求,以确保系统完全且唯一地实现它们。

代码还必须实现高水平的代码覆盖范围,并且在某些部门 - 特别是汽车 - 设计需要复杂的外部诊断,校准和开发工具是常见的。出现的问题是,防御性编码和外部数据访问等实践不是编译器识别的世界的一部分。例如,C或C ++都不会对内存损坏进行任何津贴,因此除非没有这样的损坏,否则旨在可以访问它的代码,否则在优化代码时可以简单地忽略它。因此,如果不“优化”,则防御代码必须在语法上和语义可达。

未定义行为的实例也可能引起惊喜。很容易建议他们应该简单地避免它们,但通常很难识别它们。在它们存在的地方,无法保证编译的可执行代码的行为将与开发人员的意图匹配。 “后门”访问调试工具使用的数据代表了语言不允许津贴的另一个情况,因此可能具有意想不到的后果。

编译器优化可能对所有这些区域产生重大影响,因为它们都不是编译供应商的汇款的一部分。优化可能导致明显的声音防御性代码被淘汰,其中它与“不可行性”相关联 - 该存在,其中存在于可以的路径上’通过任何可能的可能输入值进行测试和验证T.甚至更令人惊讶地,在构造系统可执行文件时,可能会在单元测试期间显示的防御代码。仅仅因为在单元测试期间已经实现了防御码的覆盖,因此并不能保证它存在于完成的系统中。

在这种功能安全的奇怪之地中,编译器可能是一个元素。这就是为什么对象代码验证(OCV)代表任何系统的最佳做法,其中有与失败相关的任何系统 - 而且确实对于只有最佳实践足够好的系统。

在汇编之前和之后

验证和验证措施通过功能安全,安全性和编码标准等IEC 61508,ISO 26262,IEC 62304,MISRA C和C ++所扮演的验证和验证实践在基于需求的测试期间展示了大量的重点来表明应用程序源代码的许多。

经验表明,如果已显示代码正确执行,则该字段中的失败概率相当较低。然而,由于这一值得称赞的努力的焦点是高级源代码(无论语言是什么),这样的方法都对编译器创建了对象代码的能力来说,这一方法很大的信念,这些代码正准确地再现开发人员故意的。在最关键的应用中,这种隐含的假设不能合理。

它是不可避免的,对象代码的控制和数据流不是导出的源代码的精确镜像,因此证明所有源代码路径都可以可靠地锻炼,不证明对象代码的相同事物。鉴于对象代码和汇编程序之间存在1:1的关系,源和汇编代码之间的比较是讲述的。考虑图1中所示的示例,其中右侧的汇编器代码已从左侧的源代码生成(使用TI编译器禁用优化)。


图1:右侧的汇编程序代码已从左侧的源代码生成,显示源和汇编代码之间的说明比较。 (来源:LDRA)

如稍后的说明,当编译此源代码时,结果汇编程序代码的流程图与源的流程码与源相比不同,因为C或C ++编译器之后的规则允许它们以任何方式修改代码,提供二进制文件表现得“好像它是一样的。”

在大多数情况下,这一原则完全可以接受 - 但有异常。编译器优化基本上是数学变换,应用于代码的内部表示。这些变换“go wrong”例如,如果假设不保持 - 例如,代码库包括未定义行为的实例的情况。

只有在航空航天行业中使用的DO-178C才会侧重于开发人员意图和可执行行为之间的危险不一致的可能性 - 即使,也不难以找到解决方案的倡导者,以清楚的潜力留下未被发现的不一致。然而,这种方法是原谅的,事实仍然是,源代码和对象代码之间的差异可能会在任何关键应用中具有毁灭性的后果。

开发人员意向与可执行行为

尽管源代码和对象码之间的差异很明显,但它们不是主要关注的问题。编译器通常是高度可靠的应用程序,而在任何其他软件中可能存在错误,则编译器的实现通常会满足其设计要求。问题是,这些设计要求并不总是反映功能安全系统的需求。

简而言之,可以假设编译器能够与其创建者的目标进行功能忠诚。但是,如下面的图2所示,这可能并非完全想要或预期,那么用与Clang编译器的编译产生的示例。


图2显示了与Clang Compiler(源代码:LDRA)的编译

很明显,在汇编程序代码中尚未在“错误”函数上的防守呼叫。

“状态”对象仅在初始化并且在“S0”和“S1”案例中进行修改,因此编译器可以推理给出“状态”的唯一值是“S0”和'S1。'编译器结论是“默认”是不需要的,因为“州”将永远不会持有任何其他值,假设没有腐败 - 并且确实,编译器确切地制定了这种假设。

编译器还决定,因为实际对象(13和23)的值未在数字上下文中使用,它将简单地使用0和1之间的值来在状态之间切换,然后使用独占“或”来更新国家价值。二进制文件遵守“仿佛”义务,代码快速紧凑。在其职权范围内,编译器做得很好。

此行为对使用链接器内存映射文件进行间接访问对象的“校准”工具具有含义,并通过调试器直接存储器访问。同样,这种考虑因素不是编译器汇率的一部分,因此在优化和/或代码生成期间不考虑。

现在假设代码保持不变,但其上下文在呈现给编译器的代码中略有变化,如图3所示。


图3:代码保持不变,但其上下文呈现给编译器的代码略有变化。 (来源:LDRA)

现在有一个附加函数,它将状态变量的值返回为整数。这次在提交给编译器的代码中绝对值13和23事项。即便如此,这些值也不在更新函数(其保持不变)内操作,并且只在我们的新“f”函数中显而易见。

简而言之,编译器继续(正确地),以便在应该使用13和23的值的情况下进行值判断 - 并且它们绝不在他们可能的所有情况下应用。

如果更改新功能以返回指向我们的状态变量的指针,则汇编程序代码会大幅度更改。因为现在alias的潜力通过指针访问,所以编译器不能再推断出状态对象发生的情况。如下面的图4所示,不能得出结论,13和23的值是不重要的,因此它们现在在汇编器内明确表示。


图4:如果更改新功能以返回指向我们状态变量的指针,则汇编程序代码会大幅度更改。它不能得出结论,13和23的值是不重要的,因此它们现在在汇编程序(源:LDRA)内明确表示。

对源代码单元测试的影响

现在考虑虚构单位测试线束的上下文中的示例。由于需要一个安全性访问被测代码的后果,因此操纵状态变量的值,因此默认不会“优化”。这样的方法在一个测试工具中完全合理,该测试工具没有与源代码的其余部分有关的上下文,这是必需的,但随着副作用,它可以伪造编译器的合法遗漏防御码。

编译器识别出通过指针,同样地将任意值写入状态变量,不能得出结论,13和23的值是不重要的。因此,它们现在在汇编程序内明确表示。在这种情况下,不能得出结论,S0和S1表示状态变量的唯一值,这意味着默认路径可能是可行的。如图5所示,状态变量的操纵实现其目标,并且在汇编程序中显而易见地对错误功能的调用。


图5:状态变量的操作实现了其目标,并且对汇编程序中的呼叫函数现在显而易见。 (来源:LDRA)

但是,此操作将不会出现在产品内的代码中,因此在完整系统中呼叫错误()并不是真正存在。

对象代码验证的重要性

为了说明对象代码验证如何有助于解决此难题,请考虑第一个示例代码片段,如图6所示:


图6:这说明了对象代码验证如何有助于解决对错误的呼叫如何在完整系统中。 (来源:LDRA)

可以说明该C代码以通过单个呼叫实现100%的源代码覆盖:

f_while4(0,3);

代码可以单行重新格式化为单个操作,并在流程图上表示为“基本块”节点的集合,每个是一系列直线代码。基本块之间的关系在图7中表示在节点之间的指示边缘。


图7:这示出了使用节点之间的指示边的基本块之间的关系。 (来源:LDRA)

编译代码时,结果如下所示(图8)。流图的蓝色元素表示呼叫尚未锻炼的代码 f_while4(0,3).

通过利用对象代码和汇编程序代码之间的一对一关系,该机制公开了对象代码的哪些部分是未开发的,提示测试员设计额外的测试并实现完整的汇编代码覆盖范围 - 因此实现了对象代码验证。


图8:这显示了代码编译时的结果。流图的蓝色元素表示呼叫尚未锻炼的代码 f_while4(0,3)。 (来源:LDRA)

显然,对象代码验证没有任何能力,以防止编译器遵循其设计规则,并无意地绕过开发人员的最佳意图。但它可以,并且这样做可以带来任何这样的不匹配来注意令人不智能的。

现在考虑在前面的“呼叫错误”示例的上下文中的那个原则。当然,完成系统中的源代码与单位测试级别的经过验证的源代码相同,因此比较将揭示任何内容。但是,对目标代码验证对已完成系统的应用在提供基本行为被表示为打算的开发人员的保证方面是非常宝贵的。

任何世界上最好的做法

如果编译器与单元测试相比,在测试线束中不同地处理代码,那么是源代码单元测试覆盖价值?答案是一个合格的“是”。许多系统已经证明了这种文物的证据,并证明了服务安全可靠。但对于所有部门的最关键的系统,如果开发过程是为了承受最详细的审查并坚持最佳实践,那么源级别单元测试覆盖必须由OCV补充。假设它满足其设计标准是合理的,但这些标准不包括功能安全考虑因素。目标代码验证目前代表了功能安全世界最有保证的方法,其中编译行为符合标准,但最多可能产生显着的负面影响。


克里斯塔普 是LDRA的现场应用工程师,拥有20多年的嵌入式软件开发经验。他于1987年毕业于达勒姆大学,并在汽车,工业管制和信息技术行业内工作的大部分职业生涯主要是作为一种自营职业顾问。自2001年以来,他曾与Misra一起参与其中,目前是Misra C ++工作组主席和屠杀工作组的积极成员。自2007年以来,他一直在LDRA,他专注于编程标准。

 

1 thought on “在外国功能安全的外国人世界中的编纂者

发表评论

本网站使用AkisMet减少垃圾邮件。 了解如何处理评论数据.

发布时间: 2021-05-13 14:54:08

最近发表