2.5 软件错误、缺陷、故障及失效
2.5.1 软件错误、缺陷及故障
2.5.1.1 软件错误
软件错误(Software Error)是指软件生命周期过程中不希望或不可接受的人为差错,是一种内部属性,相对于软件本身而言,是一种外部行为。软件错误可能导致软件缺陷,同软件失效具有直接的因果关系。常用初始错误数、剩余错误数、千(百)行代码错误数等指标进行度量。
初始错误数是指错误排除之前,软件中错误数的估计值;剩余错误数是指经过测试及纠错之后,仍然残留在软件中错误数的估计值;千(百)行代码错误数是每千(百)行有效代码中所包含的错误数,既可以用来度量初始错误数,也可以用来度量残留错误数。
错误计数依据导致软件失效的因果关系确定,而非简单的错误个数累加。假若软件失效是由一条错误语句所致,那么该语句对应于一个错误;如果软件失效是若干条错误语句共同作用的结果,则这若干条错误语句对应于一个错误;如果软件失效是因为需求规格错误所致,则该错误所涉及的语句数可能不止一条,且不一定顺序相连,可能涉及软件架构及相关文档。
错误排除之前,可能导致一次或多次软件失效,相同失效可能因为不同错误被触发所致,必须进行具体分析,不能一概而论,更不能以偏概全。软件运行过程中,以失效形式反映出来的软件错误,可能只是全部错误的一部分,另一部分隐含错误同样具有导致软件失效的可能,仅仅只是未被触发而已。
文档错误尤其是需求规格、设计文档错误是软件错误的根源,用户手册等应用文档错误可能导致用户接受错误的操作信息而导致操作失误,是软件错误的重要组成部分。一般地,操作失误不作为质量与可靠性研究范畴。一些勘误性错误可能并不直接对软件造成影响,如果将这类文档错误一并计入软件错误,将对软件质量评价的客观性、真实性带来偏差。文档错误是否计入软件错误或者是否以单独的形式加以标记和统计,需要通过甄别后区别对待。
软件生命周期过程中,可以使用直接查错法、间接查错法以及这两种方法的组合,检出错误。桌面检查、需求评审、设计评审、代码审查、编译诊断等能够直接发现错误,通过纠正评审、编译等过程中所发现的错误,能有效规避错误向下传递。间接查错法是软件调试、测试及运行过程中,有目的、有针对性地触发错误,判断和检出软件错误的有效方法。
1.错误分类
基于软件定义,软硬件之间的界限正变得越来越模糊,尤其是嵌入式系统构建,越来越多地采用软件硬化和硬件软化设计模式。例如,在特定情况下,只读存储器中的微程序、通用阵列逻辑器件中烧录的方程及时序,其错误可能引起硬件指令错误执行,故障表象为硬件特征或运行环境特征。微程序错误通常是在程序设计过程中引入的,似乎应该归类为软件错误,但它引起的却是硬件指令的错误执行,是否应将其划归到硬件错误的范畴呢?都是亟待研究解决的问题。
1)根据错误征兆分类
当将软件错误分类与其输入空间进行关联考虑时,可以根据软件错误直接表现出来的征兆进行分类。根据错误征兆的软件错误分类如表2-1所示。
表2-1 根据错误征兆的软件错误分类
对于该分类方法,某种类型错误引起的实际后果依赖于应用要求,与特定应用场景密切相关。第Ⅰ种类型错误即因系统本身辨识出不能处理正常的但超出预先规定范围的输入,拒绝该输入,不像第Ⅱ~Ⅴ种类型错误那么严重。在一个预先规定的时间范围内,系统必须对任一输入做出反应,尤其是对于实时嵌入式系统,对某个输入的拒绝可能导致灾难性的后果。
2)根据错误诱因分类
对于一个应用系统,尤其是实时嵌入式系统,错误诱因不外乎硬件或软件设计错误、环境改变等引起硬件劣化、输入错误等。设计错误、硬件劣化、输入错误构成系统的错误空间。该分类方法是以错误起因为基点,而非错误产生的影响,其先决条件是构建一个完全的错误诊断框架集。当一个设计错误发生时,即便所有输入和操作均正确无误,但也不可能产生期望的结果,且不正确的操作往往可能导致输入错误。而由于硬件劣化或环境条件改变等因素导致错误时,系统状态往往是确定且可以复现的。表2-2给出了基于诱因的软件错误发生情况及特征。
表2-2 基于诱因的软件错误发生情况及特征
3)根据错误发生时的持续时间分类
对于硬件及输入错误,可以根据错误发生时的持续时间进行分类。如果一个错误从某一特定时间开始,反复发生且能够在特定的条件下复现,称这类错误为永久错误。当某个错误发生时,系统特性产生短暂变化之后即恢复正常状态,则称这类错误为瞬时错误,这类错误持续时间短暂,引发的失效难以复现和定位,诊断和排除困难,可能导致严重后果。对于硬件中的瞬时错误,如某硬件瞬时错误将某位二进制数位取反,导致一个错误数据存储或一条错误指令执行,由此引起的错误往往难以同软件错误区分开来。
4)根据错误的表现形式及可观察性分类
根据错误的表现形式及可观察性,可将软件错误分为外部错误和内部错误。一个错误可能无法被直接观察到,除非只有诸如一个内部错误的影响传播到输出时,该错误才能在外部被观察到。如果系统采用冗余设计,并非每个内部错误都必然导致一个外部错误。内部错误和外部错误的划分,在很大程度上依赖于查错界面的选择。例如,如果一个查错界面具有分层结构,则同一个错误既可以被看成内部错误,也可以被看成外部错误。
5)根据应用结果分类
软件设计过程中,根据应用结果将软件功能划分为主要功能、基本功能、次要功能、辅助功能并加以区别对待,有利于突出重点。次要或辅助功能失效可能不会影响系统使命任务的遂行,如果一个错误只影响软件系统的次要或辅助功能,该错误就是非关键性的。如果将软件错误划分为关键性错误和非关键性错误,同样有利于关键问题的解决,这正是软件测试的出发点。
6)根据软件生命周期过程分类
基于软件生命周期过程,将软件错误划分为分配需求错误、需求错误、设计错误、实现错误、测试错误、验收与交付错误、运行与维护错误等类型。软件生命周期过程中,如果能够对每个阶段的错误形态进行定义并进行充分的测试验证,对系统质量保证及改进事半功倍。这正是软件测试与开发过程分离、注重验收测试、忽视测试左移与回看等广受诟病的重要原因。
7)根据软件构成成分分类
根据软件构成成分,可将软件错误分为程序错误、数据错误和文档错误3类。
8)根据错误严重程度分类
所有错误均可能导致软件失效,但其严重程度则具有显著差别。依据相关标准规范,基于系统服务功能丧失、人员伤害、设备损坏、环境破坏的程度,将软件错误划分为致命错误、严重错误、一般错误等不同等级或类型。基于错误严重程度的软件错误分类粒度,不同标准规范具有一定差异,但分类方法大同小异。
2.软件生命周期过程错误表征
1)需求识别、需求获取与需求分析错误
对问题进行准确定义、抽象处理及严格的数学描述,是我们面临的重大挑战。何况,软件错误征兆、错误诱因、失效机理异常复杂,难以预先定义统一的标准。而基于软件状态与预先定义标准的比较,辨识软件状态并对其给定状态进行评价,无异于无源之水。
需求识别、需求获取及需求分析,是通过对实际问题的归纳和抽象,剔除不涉及问题本质的次要因素,抽取与具体问题相关的要素,对问题进行定义和抽象描述,构建需求规格。在此过程中,可能遗漏、曲解、错误定义用户需求,甚至会掩盖问题的本质。统计表明,软件错误大都是由于对系统需求识别不充分、描述不准确以及对问题理解偏差所致,并非软件设计所致。
2)软件设计错误
(1)设计文档错误。
(2)架构笨重。
(3)程序说明的错误中断。
(4)不完全的逻辑。
(5)模块之间解耦不够。
(6)安全性设计不足。
(7)特殊情况被忽略。
(8)缺乏对错误处理能力的考虑。
(9)对时间、资源等疏忽。
3)编码实现错误
(1)不符合编码规范。
(2)语法错误。
(3)初始化错误。
(4)参数混淆。
(5)循环计数错误。
(6)对判定结果的不正确处理。
(7)变量重复或未定义便加以使用。
(8)变量名书写错误。
(9)数组类型和维数说明不正确。
尽管开发技术对软件设计与实现错误具有直接影响,而更加突出的问题是团队笨重,难以实现有效的扁平化,导致沟通困难。与此同时,与软件开发、编码实现及软件测试等人员的素质和能力相关,尤其是对复杂问题处理更是如此。统计表明,软件设计与编码实现阶段所检出的逻辑错误数与系统分析、系统设计阶段的时间成正比。
4)软件运行错误
通常,当讨论软件运行错误时,总是假定一个正确的软件,加上正确的输入,得到正确的结果。这不仅是应该的,而且也是可能的,否则,我们将对所交付的软件失去信心。但受制于软件测试技术、能力、成本等因素,完备软件测试还只是一个梦想。因此,在软件系统运行过程中,仍然可能发现错误,如不正确的初始化、数组越界、数据溢出、内存泄漏、防误操作设计、硬件缺陷等导致的软件失效。基于使用质量视角,运行阶段的错误表征,更多的是与运行环境、使用流程、功能完备、系统效能、操作使用、人机交互等与系统能力、用户体验相关的问题。而这些问题的定义往往超越了错误的范畴。基于缺陷驱动的测试与基于能力驱动的测试,存在着本质的差别。这是软件测试发展的重大跨越。
5)瞬时硬件故障
瞬时硬件故障可能产生不正确的数据或控制流,具有与软件错误相似的征兆,可能因此被裁定为软件错误。瞬时硬件故障是系统故障的诱因,特别是当通过诊断软件检查硬件且显示硬件功能正常时,更是如此。例如,某嵌入式系统显示界面同时进行背景填充和汉字输出时,某些汉字出现多余笔画,直接表象是软件错误所致,而实际上是因为DRAM芯片TC5118160BJ-60的瞬时故障,使得进行OpenGL作图时,16MB DRAM作为深度缓存(Z Buffer)与纹理映射存储器,用于缓存用户数据、存放字库,导致该瞬时故障发生。
瞬时硬件故障大多是由于间歇性干扰、硬件渐变等原因所致,发生时间非常短暂,定位及排除困难,对于不具备硬件查错功能的系统,瞬时硬件故障可能引起更多问题,甚至可能演变为系统故障的主要诱因。工程上,通过老化试验能够估计得到瞬时硬件故障的发生概率。Ball和Hardie对这类故障进行深入研究后指出:对于瞬时硬件故障,控制部件的反应比算术部件更加敏感;在一条指令执行期间,对于出现在控制部件中的故障,被立即查出的概率较算术部件小一个数量级;瞬时硬件故障仅仅只有在其持续时间大于一个周期时,才是至关重要的。
3.典型软件错误
1)需求错误或变化
(1)要求全新的功能(包括要求新的硬件)或增加新的功能。
(2)对硬件环境及外设的要求。
(3)对处理器的要求。
(4)对输入/输出及接口的要求。
(5)对内存、存储资源及容量的要求。
(6)对操作系统功能的特殊要求。
(7)对数据库管理及完整性的要求。
(8)对安全性的要求。
2)文档错误
(1)程序限制。
(2)操作过程。
(3)流程图或问题分析图(Problem Analysis Diagram,PAD)与编码之间的区别。
(4)错误信息。
(5)程序应有功能说明。
(6)输出形式的要求。
(7)文档的完整性及正确性。
3)逻辑错误
(1)问题抽象错误。
(2)不正确或无效逻辑以及简单逻辑复杂化和错误的逻辑分支。
(3)不完全的处理。
(4)死循环。
(5)逻辑或条件不完全的测试。
(6)对上、下限的判断错误。
(7)下标未经校验。
(8)特征值或特殊数据未经测试。
(9)重复步长的不正确判断。
4)数据处理错误
(1)向故障存储介质或接口读/写数据。
(2)数据丢失、无法存储或传输。
(3)数据、下标、特征值未加设置,或不正确设置,或不正确初始化,或错误更改。
(4)额外项(表、数组)的产生。
(5)二进位信息处理错误。
(6)错误变址。
(7)数组类型转换错误。
(8)内部变量定义错误、设置或使用。
(9)对不存在的记录进行数据查找。
(10)越限。
(11)数据链接错误。
(12)溢出或对溢出的错误处理。
(13)读出错误。
(14)错误分类。
(15)错误覆盖。
5)操作覆盖错误
(1)测试执行错误。
(2)使用错误的主结构。
(3)数据准备错误。
6)在要求满足方面的问题
(1)要求的能力被忽略或对相应要求考虑不周。
(2)未达到所要求的功能。
(3)超过规定的运行时间。
(4)规定的时间内不释放资源。
7)计算错误
(1)使用不正确的表达式与习惯表示法。
(2)数学模型错误。
(3)错误或不精确的运算结果。
(4)算法选择问题。
(5)非期望的运算结果。
(6)下标计算错误。
(7)混合运算次序错误。
(8)向量运算错误。
(9)符号习惯表示法错误运用。
8)用户接口错误
(1)通信协议不一致或不协调。
(2)对输入数据的不正确解释。
(3)拒绝接收或无法使用有效的输入数据。
(4)本来已被拒绝的输入数据又被程序所用。
(5)不使用读出的输入数据。
(6)接收并处理非法输入数据。
(7)对合法输入数据的不正确处理。
(8)接口设计不完善。
(9)不适当的中断与再启动。
9)程序接口错误
(1)要求错误的参数。
(2)无法使用可用参数。
(3)调用次序紊乱。
(4)初始化错误。
(5)程序之间通过错误的数据区进行通信。
(6)程序不兼容。
10)程序/系统软件接口错误
(1)操作系统接口错误。
(2)程序对系统支持软件的不正确使用。
(3)操作系统本身的问题限制程序功能的发挥。
11)输入/输出错误
(1)输出与设计要求不一致。
(2)输出信息丢失或丢失数据项;输出形式不正确;重复输出;输出域大小不适当。
(3)设计中未定义必要的输出形式。
(4)排错时的输出问题(与设计文档有关)。
(5)打印控制错误。
(6)行/页计数错误。
(7)应输出的出错信息被删除。
(8)标题输出问题。
2.5.1.2 软件缺陷
软件缺陷(Software Defect)是因人为差错或其他客观原因使得软件隐含导致其在运行过程中出现不希望或不可接受偏差的需求定义、软件设计、编码实现等错误。软件缺陷和错误有着相近的含义。当软件运行于某一特定环境时出现故障,称缺陷被激活。软件缺陷存在于软件内部,是一种静态形式。
软件生命周期过程中,软件开发组织及测评机构应建立软件缺陷库,将其作为重要资产进行跟踪管理。一般地,软件缺陷管理流程如图2-14所示。
图2-14 软件缺陷管理流程
1.软件缺陷及行为
软件缺陷是软件测试关注的焦点。不仅要关注程序、文档、数据等缺陷,还要面向应用系统,关注软件修改、升级维护引入及僵尸代码唤醒、开源代码应用、操作使用等缺陷。软件缺陷的内涵及演变如图2-15所示。
图2-15 软件缺陷的内涵及演变
2.软件缺陷分类
鉴于软件缺陷同错误的相关性和相似性,可以按错误分类方法对软件缺陷进行分类。面向软件缺陷的不同表现形式,基于总体视角,将软件缺陷分为语法缺陷和语义缺陷两类。语法缺陷是指软件不符合程序设计语言的语法要求以及应遵循的标准、规则和约定,语义缺陷则是指软件未正确地表达应表达的含义,包括初始化缺陷、接口缺陷等形式。基于软件成分,可以将软件缺陷划分为程序缺陷、数据缺陷、文档缺陷三种类型。基于软件测试视角,给出如表2-3所示的软件缺陷的工程化分类,同时对不同缺陷类型的表象进行描述。
表2-3 软件缺陷的工程化分类
同软件错误一样,基于缺陷的严重等级,可以将软件缺陷分为致命缺陷、严重缺陷、一般缺陷三种类型。基于严重等级的软件缺陷分类如表2-4所示。
表2-4 基于严重等级的软件缺陷分类
2.5.1.3 软件故障
软件故障(Software Fault)是指在规定的条件下,软件系统运行过程中,出现可感知的不正常、不正确或不按规范执行的状态。软件故障仅与设计和编码实现有关。在数据结构或软件输出中的表现称为软件差错。这里,可通过如下示例,展示软件的故障及其形态。
基于故障持续时间,软件故障可分为永久性故障和瞬时故障;基于运算特性,软件故障通常由计算错误、逻辑错误、数据处理错误、接口错误、数据定义错误、数据库错误、输入/输出错误以及文件资料错误等导致,可将软件故障对应地划分为这八类。