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