当嵌入式开发人员测试他们的软件时,有多种力量在起作用。由于对更大的计算工作负载、更广泛的连接以及改进的安全性的需求,系统的复杂性不断增加,这使得开发人员更难根据需求验证代码。随着发布时间的缩短,测试团队努力使传统的测试方法适应更大的复杂性和规模。
需要一种新的测试方法,团队正在寻求数学上证明的代码正确性,以显着提高对其应用程序的信心。要了解当今的产品目标与传统测试方法之间的差距,考虑复杂性如何影响测试会有所帮助:
覆盖。随着软件复杂性的增长,创建涵盖足够级别的代码库(包括函数、语句、路径、决策和条件)的测试变得越来越困难。
规模。无论测试范围(特性、组件、库或功能)如何,单元越多,测试它们所需的时间和资源就越多。
速度。传统的测试开发和执行实践无法跟上发布时间表的步伐,不可避免地迫使在测试覆盖率和时间之间进行权衡。
长期以来,人们一直认为接近 100% 的代码覆盖率是不可能的,因为这样的目标极难实现且运行成本高昂。单元测试、渗透测试、动态分析 – 所有传统技术都需要大量的时间和资源来执行,并导致对系统中错误和漏洞的不完整视图。
随着软件技术和计算能力的最新进步,这种信念现在已成为一个被证明的神话。学术和行业研究人员已经开发出数学上严格的技术,称为形式化方法,可实现高达 100% 的代码覆盖率并保证系统的正确性 - 现在可供企业就绪平台中的安全和安保关键型开发团队使用。
了解基于正式方法的测试工具
在纸面上,形式化方法明确证明代码没有错误和安全漏洞等问题。这些方法使用严格指定的数学模型,根据精确定义的规范验证软件的属性和行为。换句话说,形式化方法可以找到代码中出现的所有问题。
在实践中,任何开发人员都可以使用且负担得起基于企业级正式方法的测试工具。它们被称为详尽的静态分析工具,经过精心设计和验证,可将正式方法的强大功能集成到安全和安保关键型开发团队的现有验证和确认流程中。
与传统的测试和静态分析方法相比,这些工具有几个优点:
高达 100% 的应用程序覆盖率,涵盖所有可能的功能、语句、路径、决策和条件。
高达 100% 的输入覆盖率,涵盖被测单元范围内的所有可能值。
数学保证代码中没有未定义的行为(错误和漏洞),导致部署中零问题。
零漏报,因此开发人员可以增强发现所有问题的信心。
误报率低至零,这意味着开发人员花在追逐并非真正问题上的时间更少。
显著缩短测试时间,提高资源消耗效率。
图 1 说明了差异。传统的测试方法通常是测试用例开发和算法设计的“最大努力”尝试,受到人力和项目进度的限制。这会导致测试每次运行执行一个代码分支,并限制团队在给定测试阶段可以覆盖的内容。以正式方法为后盾的详尽静态分析可在单次测试运行中并行分析所有分支,将覆盖率提高到 100%,并显著缩短测试时间。
图 1:传统测试方法(左)和声音静态分析(右)之间的代码路径比较。访问的段以橙色显示;未访问的段为黑色。
详尽的静态分析可以为开发人员提供一种强大的方法来管理软件复杂性,从而极大地改变他们对软件复杂性的看法。
详尽的静态分析如何提供帮助
传统测试方法的一个限制是它们的状态空间覆盖,即数据值和输入、控制和数据流的不同组合的数量以及它们可以覆盖的输出路径的固有限制。例如,传统的测试方法通常会在给定预期输入的情况下测试预期输出的函数。一些静态分析工具对此进行了扩展,以涵盖更广泛的输入和输出。但由于测试设计、实现和计划约束,这些工具无法测试所有可能的行为。
下面的代码示例演示了一个递增数组中的单元格值的 C 函数。
典型的单元测试将根据函数的要求进行验证,检查函数是否递增了输出数组中的单元格值,并根据结果报告通过或失败。此测试不一定会检查数组索引 *p 是否由于系统中意外或不希望的副作用而导致越界内存访问 - 就像本代码示例中由于 while 循环中指定的不正确条件而发生的那样。
尽管存在缓冲区溢出,但针对要求的传统测试将在调用函数后验证数组是否为 {2, 4, 6, 8},并且始终通过,如以下控制台输出所示:
除非测试设计者考虑越界数组访问的可能性,否则永远不会识别此缓冲区溢出。
这些类型的细微缺陷可能导致内存损坏,从而导致潜在的错误、崩溃或应用程序漏洞 - 传统测试方法不可见,但可以通过详尽的静态分析工具发现,如图 2 所示。该工具检测到数组开头后有 16 个字节的写入:缓冲区溢出。
图 2:在 TrustInSoft 详尽静态分析工具中查找结果的屏幕截图。
这种内存损坏可以通过更详细的测试用例来揭示,其中越界写入条件会影响变量名称的值,即使它不参与测试的函数,如以下控制台输出所示:
但是,开发团队很少实现此级别的测试深度,尤其是当代码比此示例更复杂时。
硬件感知在静态分析中的重要性
更 高级 的 详尽 静态 分析 工具 为 验证 和 确认 活动 带来 硬件 感知, 从而 实现 更 准确 和 高效 的 测试 覆盖率。硬件感知的重要性怎么强调都不为过,因为编译器实现、硬件架构和内存对齐的差异可能导致测试条件和代码行为大不相同。例如:
在 64 位目标上,long 通常为 64 位,int 通常为 32 位。
在 32 位目标上,long 和 int 通常都是 32 位。
这些硬件差异会影响测试条件、输入和路径,如以下代码示例所示:
如果没有硬件感知,测试或分析方法将无法确定最后一条语句是否导致整数溢出(32 位目标)或不导致整数溢出(64 位目标)。在某些情况下,测试将执行比必要的更多的运行,以涵盖硬件支持范围之外的条件。在其他情况下,测试可能只是错过潜在的溢出。硬件感知静态分析在 100% 覆盖率和实现覆盖率所需的最少测试用例数量之间提供了完美的平衡。
另一个关键的硬件差异是字节序,如以下代码示例所示:
根据底层硬件的字节序,变量 c 将设置为 0xBE(大端序)或0xEF(小端序)——这是测试执行的关键区别。
这种微妙的差异可能会导致灾难性的结果。请考虑将以下语句添加到上述代码示例中的情况:
在大端系统上,此语句将导致除以零条件,并可能导致应用程序崩溃或其他不良行为。在小端系统上,此语句是有效的。了解这些差异的测试方法可以得出更准确的结果。
包含硬件感知的详尽静态分析工具还具有以下优点:
开发人员可以运行硬件感知分析,而无需将物理目标连接到主机。
目标测试可以在开发生命周期的早期运行,甚至在物理硬件可用之前。
开发团队可以提高测试能力并降低成本,因为不需要每个主机和开发人员都使用物理硬件。
详尽静态分析的未来
优先考虑详尽静态分析的嵌入式开发团队(代码覆盖率高达 100%,准确性远高于传统测试)将从其测试投资中获得最高价值。那些现在能够加入的开发人员将能够更好地提供更高质量的代码,并随着时间的推移提高测试效率。
从长远来看,从这种严格的测试中获得的结果和知识将导致“零问题”保证。这些原则将在开发过程的早期带来更强的可测试性,以支持安全和安保关键型产品要求和设计,并显着降低现场软件故障和漏洞的可能性。
编辑:黄飞
全部0条评论
快来发表一下你的评论吧 !