收藏 分销(赏)

软件分析技术进展.doc

上传人:人****来 文档编号:3550691 上传时间:2024-07-09 格式:DOC 页数:26 大小:232.54KB 下载积分:10 金币
下载 相关 举报
软件分析技术进展.doc_第1页
第1页 / 共26页
软件分析技术进展.doc_第2页
第2页 / 共26页


点击查看更多>>
资源描述
软件分析技术进展*资助项目:国家重点基础研究发展规划973项目(No. 2023CB320703);国家自然科学基金委创新研究群体研究科学基金项目(No:60821003);国家863高技术项目(No. 2023AA01Z175) 梅宏1 王千祥1 张路1 王戟2 1.北京大学信息科学技术学院,高可信软件教育部重点实验室,北京100871 2.国防科技大学计算机学院,并行与分布解决国防科技重点实验室, 长沙 410073 摘 要 软件分析技术的研究已有较长历史,相关成果也在软件生命周期的不同阶段中得到了广泛应用。软件生命周期中不同活动所需要的软件分析技术既不完全相同,又有许多交叠,且不同的分析技术之间互相影响。文章在讨论了软件分析的基本概念之后,重要从静态分析与动态分析两个方面介绍了一些重要的软件分析技术,以及部分相关分析工具。结合软件的质量问题,文章还探讨了一些分析技术与软件质量属性的相关性,以便于人们在分析特定的软件质量属性时,选取合适的技术与工具。最后,文章展望了软件分析技术的发展趋势。 关键词 软件分析,静态分析,动态分析,软件质量 中图法分类号 TP301 1. 引言 软件是一种十分特殊的人工制品:它是人类“智力活动”的产物,是对客观事物的虚拟反映,是知识的固化与凝练。尽管软件迄今已有50数年的发展历史,但目前人们对于软件的许多结识还十分有限。例如:对于任何一个给定的软件,我们能否完全了解它的特性?软件分析就是一个以软件特性为关注点的研究领域。“分析”,通俗来说,是以某种方式将复杂对象分解为更小的部分,以更好地理解该对象的过程。分析技术很早就被应用于数学、逻辑等方面的研究,近代以来逐步被更多的学科(例如:化学、物理等)所大量采用。软件作为一个新发展起来的学科,在研究过程中引入分析技术是十分自然的。目前软件生命周期中的许多活动(分析、设计、实现、测试、部署、维护等)都离不开分析技术。然而,软件分析的能力是有限的:对于任何一个有一定规模的软件,希望获得关于它的完备描述通常是不现实的[18]。特别是,对于自动分析而言,许多问题是不可鉴定的。其中最典型的例子是停机不可鉴定问题:不存在一个这样的算法,对于任意的图灵机以及任意的输入,可以判断该图灵机是否停机[64]。但从软件分析这么数年所取得的进展可以看出,尽管软件分析的能力有限,它仍然是软件领域十分有用的技术:将程序从高级语言向机器语言的翻译过程需要分析,判断一个程序是否符合需求规约需要分析技术,想了解程序是否存在安全漏洞需要分析技术,维护过程更是需要大量的分析技术,等等。 本文将软件分析定义为“对软件进行人工或者自动分析,以验证、确认、或发现软件性质(或者规约、约束)的过程或活动”。下面对上述定义中几个术语进行解释。一方面是“软件”:软件最初重要是指程序,后来逐步扩大到文档等其它形态软件制品。软件分析也从程序分析发展到了更大的范围,例如:对文档(含需求规约、设计文档、代码注释等)的分析、对运营程序的分析,等等。“自动”也是很重要的概念:软件分析的历史几乎与软件的历史同样长:自从有了软件就有了软件分析。最初的分析重要是人工进行的,但人工分析往往需要花费大量的时间与精力,因此,后来人们越来越多地关注自动分析。其中,编译技术的发展大大带动了软件的自动分析技术,目前的许多分析技术都可以在编译技术中找到基本雏形。所谓“验证”(Verification),是要回答“软件制品是否与软件需求规约一致”的问题,而“确认”(Validation)则要回答“软件的特性是否符合用户需求”的问题。在英文中,人们经常用“Do the thing right”来解释“验证”,而用“Do the right thing”来解释“确认”。“发现”(Discover)是指在没有事先设定软件某个性质的前提下,通过度析发现软件的某种性质。之所以强调“性质”,是由于分析的结果通常表达为软件是否符合或者具有某种性质(或者规约、约束),而这种性质不是软件自身自明的。 在本文讨论的软件分析中,分析对象仅限于软件制品,不涉及对软件过程、软件人员与软件组织等的分析。目前与软件分析相关的综述性文献中,多数只对软件分析的一个子集进行比较进一步的介绍。例如[1]集中在对源代码分析的介绍,[2]重要介绍形式化的分析方法,[53]着重从语义的角度介绍程序分析,[54]集中在模型为中心的程序分析上。本文在这些工作的基础之上,尝试对软件分析涉及的重要方法进行尽也许全面的总结、分类。此外,考虑到近年来软件质量为人们所热切关注,本文在介绍分析技术之外,特别关注那些与质量相关的分析技术,并结合不同的软件质量属性,探讨不同的质量属性适合运用什么类型的分析技术。最后,文章结合软件形态、软件运营环境等几个驱动力对软件分析技术的发展趋势进行展望。 2. 软件分析技术 软件分析通常是此外一个更大的软件生命周期活动(例如:开发、维护、复用等)的一部分,是实行这些过程的一个重要环节: a)在开发阶段,对正在开发的软件进行分析,以快速地开发出高质量的软件,例如:了解开发进展、预测开发行为、消除软件缺陷、程序变换等等; b)在维护阶段,对已经开发、部署、运营的某个软件进行分析,以准确地理解软件、有效地维护该软件,从而使软件提供更好的服务; c)在复用阶段,对以前开发的软件进行分析,以复用其中有价值的成分。上述各过程差异较大,需要的分析技术也多种多样。这导致目前的软件分析内容十分丰富,且互相之间的界线也不甚清楚:有些分析过程需要此外某个或某些分析的支持;有些分析针对具体的性质开展,而有些分析方法则可以支持多种性质的分析。 2.1. 软件分析分类 为了对软件分析有个比较全面的了解,对其进行合理的分类是十分必要的。对软件分析进行分类的维度有很多。其中,分析对象是最重要的准则之一,即软件分析是对什么制品进行分析?从大的方面看,软件分析可以对代码进行,也可以对模型(需求规约、设计模型、体系结构等)、文档甚至注释进行。代码可以进一步分为源码与目的码,目的代码又具有静态与运营态两种存在方式,而运营态的代码又可以进一步区分为离线的运营与在线的运营。除分析对象维度之外,还可以从方法学(结构化软件、面向对象软件、面向构件软件等)、并行限度(串行软件、并行软件)等其它维度划分软件分析的内容。 本文一方面以分析过程“是否需要运营软件”为准则,将软件分析技术划分为静态分析技术与动态分析技术两大类,然后又在每一大类技术下面做进一步的划分。图1是综合考虑静态、动态分析技术给出的一个分析过程示意图。 图1 静态分析与动态分析的基本过程 2.2. 静态分析 静态分析是指在不运营软件前提下进行的分析过程。静态分析的对象一般是程序源代码,也可以是目的码(例如JAVA的 byte code),甚至可以是设计模型等形态的制品。静态代码分析重要可以应用于如下几个过程:1)查找缺陷,以消除软件中存在的缺陷;2)程序转换,以实行编译、优化等过程;3)后期的演化与维护;4)动态分析,等等。 根据各种分析方法使用的广泛限度以及分析方法的相近性,本文将重要的代码静态分析划分为四类:基本分析、基于形式化方法的分析、指向分析与其它辅助分析(见图2)。其中,基本分析是一些常见的分析,例如语法分析、类型分析、控制流分析、数据流分析等,是多数编译器都包含的分析过程(词法分析由于相对简朴而没有引入);而基于形式化方法的分析则在分析过程中大量采用一些数学上比较成熟的形式化方法,以获得关于代码的一些更精确或者更广泛的性质。指向分析多数与指针密切相关,由于在静态分析中长期受到较多的关注,因此单独作为一类。其它辅助分析则包含了一些单独分析的目的性不是很强,但可认为前面几类分析提供支持的一些分析方法。需要指出的是,这不是一个严格的分类,而仅仅是为了便于人们比较全面地了解静态分析,对一些重要的、具有共性的静态分析进行归类而得到的一个结果。 图2 重要的静态分析技术 2.2.1. 基本分析 1)语法分析(Syntax Analysis)。语法分析是按具体编程语言的语法规则分析和解决词法分析程序产生的结果并生成语法分析树的过程。这个过程可以判断程序在结构上是否与预先定义的BNF范式相一致,即程序中是否存在语法错误。程序的BNF范式一般由上下文无关文法描述。支持语法分析的重要技术涉及算符优先分析法(自底向上)、递归下降分析法(自顶向下)和LR分析法(自左至右、自底向上)等。语法分析是编译过程中的重要环节,也是多数其它分析的基础:假如一个程序连语法分析都没有通过,则对其进行其它的分析往往没故意义。 2)类型分析(Type Analysis)。类型分析重要是指类型检查(Type Checking)。类型检查的目的是分析程序中是否存在类型错误。类型错误通常是指违反类型约束的操作,例如让两个字符串相乘,数组的越界访问,等等。类型检查通常是静态进行的,但也可以动态进行。编译时刻进行的类型检查是静态检查。对类型分析的支持限度是划分编程语言种类的准则之一:对于一种编程语言,假如它的所有表达式类型可以通过静态分析拟定下来,进而消除类型错误,则这个语言是静态类型语言(也是强类型语言)。运用静态类型语言开发出的程序可以在运营程序之前消除许多错误,因此程序质量的保障相对容易一些(但表达的灵活性弱一些)。 3) 控制流分析(Control Flow Analysis)。控制流分析的目的是得到程序的一个控制流图(Control Flow Graph)。控制流图是对程序执行时也许通过的所有途径的图形化表达。通过根据不同语句之间的关系,特别是考虑由“条件转移”、“循环”等引入的分支关系,对过程内的一些语句进行合并,可以得到关于程序结构的一些结果。一个控制流图是一个有向图:图中的结点相应于程序中通过合并的基本语句块,图中的边相应于也许的分支方向,例如:条件转移、循环等等,这些都是分析程序行为的重要信息。 4) 数据流分析(Data Flow Analysis)。数据流分析试图拟定在程序的某一点(语句),关于各个变量的使用或者也许取值情况。数据流分析一般从程序的一个控制流图开始。数据流分析重要有前向分析(Forward Analysis)、后向分析(Backward Analysis)两种方法。前向分析的一个例子是可达定义(reaching definitions)。它计算对于程序的每一点,也许到达该点的定义的集合。后向分析的一个例子是活跃变量(live variables)。它计算对于程序的每一点,程序后面的语句也许读取且没有再次修改的变量。这个结果对于消除死代码(dead code)很有用:假如一个变量在某个阶段被定义后,后面的语句一直不会用到这个定义,那么这个定义就是死代码,应当从程序中删除。基于格(lattice)与不动点(fixpoint)理论的数据流分析是目前被广泛使用的技术:一方面对控制流图中的每个节点建立一个数据流等式(equations),并根据分析目的构造一个具有有限高度的格 L ,然后不断反复计算每个节点的输出,直到达成格的一个不动点。许多编译器为了进行编译优化而引入了数据流分析技术。 由于上述四种基本分析是多数编译器包含的内容,因此很早就得到了较进一步的研究[62]。这些分析过程尚有一个共同特点是分析的输入仅仅是软件代码,不需要提供图1中的“系统性质”。或者说,基本分析技术所需要的“系统性质”都是最基本的性质。例如语法分析相应的“系统性质”就是编程语言的BNF范式,类型分析相应的“系统性质”是预先定义的类型约束,数据流分析相应的“系统性质”是编程语言的基本约定,等等。而下面要讲到的形式化分析、指向分析则通常要事先提供待验证的性质,例如:某个变量的取值是否在某个范围内、某两个变量名是否指向相同的内存实例、等等。 2.2.2. 基于形式化方法的分析 为了提高分析的准确度,获取关于程序的更多性质,许多研究人员借用形式化方法来扩展基本分析技术。代表性技术有模型检查、定理证明、约束求解、抽象解释等。 1) 模型检查(Model Checking)。模型检查用状态迁移系统表达系统的行为,用模态/时序逻辑公式描述系统的性质,然后用数学问题“状态迁移系统是否是该逻辑公式的一个模型”来鉴定“系统是否具有所盼望的性质”[32]。模型检查虽然在检查硬件设计错误方面简朴明了且自动化限度高,然而被应用在软件程序分析与验证时却存在着难以解决的状态空间爆炸问题。此外,由于模型检查所针对的检核对象是模型而非程序自身,任何在将程序向模型转化的过程中所使用的抽象技术以及转化工作都有也许使模型与程序不一致或者存在偏差,从而导致最终的检查结果无法准确反映实际程序中存在的错误情况。更多关于模型检查的进一步讨论可以参见[32]。支持模型检查的代表性软件分析工具为SLAM[23]、MOPS[24]、Bandera[25]和Java PathFinder2 [26]。 2) 定理证明(Theorem Proving)。自动定理证明通过将验证问题转换为数学上的定理证明问题来判断待分析程序是否满足指定属性 [1],是众多分析方法中最复杂最准确的方法。然而,一阶逻辑是半可鉴定的,理论分析结果表白,机械化的定理证明过程并不保证停机。此外,为了获取指定的属性以实现有效的证明,这些工具都规定程序员通过向源程序中添加特殊形式的注释来描述程序的前置条件、后置条件以及循环不变量。这无疑增长了程序员的工作量,也导致该方法难以广泛应用于大型应用程序。使用定理证明的代表性软件分析工具为ESC[27]和ESC/Java[28]。 3) 约束求解(Constraint Solving)。基于约束求解的程序分析技术将程序代码转化为一组约束,并通过约束求解器获得满足约束的解[48]。初期的研究表白,面向途径的测试数据生成可以很好地归结为约束求解问题。后来,学者们又发现程序中不变式的分析也可以归结为约束求解问题。最新的研究表白,许多其的程序分析问题也可以归结为约束求解问题:由于从程序获得的约束通常采用一阶或二阶的形式表达,可以进一步将其转换成约束求解器可解决的形式。支持约束求解的代表性软件分析工具为SAT/SMT Solver[49]。 4) 抽象解释(Abstract Interpretation)。程序的抽象解释就是使用抽象对象域上的计算逼近程序指称的对象域上的计算,使得程序抽象执行的结果可以反映出程序真实运营的部分信息。抽象解释本质上是在计算效率和计算精度之间取得均衡,以损失计算精度求得计算可行性,再通过迭代计算增强计算精度的一种抽象逼近方法。通过不断迭代,抽象解释最终为程序建立一个抽象模型。假如抽象模型中不存在错误,就证明其相应的源程序中也不存在错误。具有抽象解释分析功能的代表性分析工具为Proverif[29]和ASTREE[30]。 形式化支持的分析技术在分析软件的某个性质时,需要一方面对该性质进行形式化的描述,然后将这个描述与软件制品一起作为输入提供应分析工具。其中,模型检查一方面被用于对软件的模型进行分析,后来有研究人员通过从代码中提取模型,然后将模型检查技术应用于代码分析。定理证明重要对静态代码比较合用。约束求解多用于输入数据的生成。基于抽象解释理论的形式化方法是对大规模软件、硬件系统进行自动化分析与验证的有效途径之一,已经被广泛地应用于大型软件与硬件系统的验证研究中。 2.2.3. 指向分析 1) 别名分析(Alias Analysis)。别名分析重要用于拟定程序中不同的内存引用(reference)是否指向内存的相同区域。在编译过程中,这可以帮助判断一个语句将影响什么变量。例如,考虑如下的代码: ...; p.foo = 1; q.foo = 2; i = p.foo + 3; ...。假如 p和q不是别名,那么 i = p.foo + 3; 等价于 i = 4; 假如 p和q是别名,那么 i = p.foo + 3; 等价于 i = 5; 这样就可以对代码进行等价优化。别名分析又可以分为基于类型的分析与基于流的分析。前者重要用于类型安全(type safe)的语言,后者则重要用于具有大量引用与类型转换的语言[3]。 2) 指针分析(Pointer Analysis)。指针分析试图拟定一个指针到底指向哪些对象或者存储位置,特别是,在某个语句处是否也许为空。由于受到可鉴定性问题的限制,加上分析过程中时间、存储等的限制,多数的指针分析方法都在分析过程中进行“近似”或者“简化”,并导致分析结果精确性不够。事实上,上面的别名分析与下面的形态分析、逃逸分析都与指针分析密切相关。 3) 形态分析(Shape Analysis)。形态分析重要用于发现或者验证程序中动态分派结构的性质。对于一个具体的程序,形态分析将为其构造一个形态图(shape graph),用于列出每个指针也许指向的目的,以及目的之间的关系。形态分析可以认为是指针分析的一种, 但比一般的指针分析精确:形态分析可以拟定一个小一些但是更精确的指向集合。例如在Java 程序中,可用来保证一个排序算法对的地对列表进行了排序;在C程序中,可以用来分析一个内存是否被对的地释放。尽管形态分析很强大,但往往需要花费较多的时间[4]。 4) 逃逸分析(Escape Analysis)。逃逸分析计算变量的可达边界。对于一个方法 m 中的一个变量,假如变量是在调用方法 m 时创建的,但在 m 的生命周期之外可以获得该变量,我们就说这个变量逃逸了方法 m。类似地,一个变量逃逸了一个线程 t, 假如在 t 之外的一个点能通过一个引用访问到该变量。逃逸分析传统上被用于查找一些变量,它们只存在于为它们分派内存的方法或线程的生命周期内:前者允许变量在运营时的栈(stack)上,而不是堆(heap)上分派内存,这样就可以减少堆的碎片与垃圾回收负载。后者被用于进行优化,以避免高成本的异步操作。逃逸分析检查引用的赋值与使用(assignments and uses )以计算每个变量的逃逸状态。每个变量可以被赋予3个也许逃逸状态中的一个:全局逃逸、参数逃逸或者捕获。当一个变量是全局可达的(例如被赋值给了一个静态域)时,这个变量被标记为全局逃逸;假如变量是通过参数或者被返回给调用者方法,它被标记为参数逃逸;一个不逃逸的变量被标记为捕获。逃逸分析重要用于效率分析[22]。 与基本分析技术相比,指向分析通常与应用程序的某个特定性质密切相关。这类分析一般是以基本分析(特别是数据流分析)为重要分析框架,为了提高分析精度而提出的技术,且分别结合了编程语言的不同特点。例如:别名分析运用的变量引用、形态分析运用的指针等等。这也导致了这些分析技术分别适合由不同编程语言实现的程序。此外,这些分析技术尽管可以自动进行,但在分析之前通常需要较多的人工介入,例如,指定对哪些变量进行分析、提供对什么性质进行分析等等。 2.2.4. 其它辅助分析 1) 符号执行(Symbolic Execution)。符号执行通过使用抽象的符号表达程序中变量的值来模拟程序的执行[14, 31]。其特点在于通过跟踪被模拟的各条执行途径上变量的实际取值,把分析工作局限在实际可达的途径上,从而使得到的结果更贴近程序实际执行情况,并为程序员提供更为准确的与检出的缺陷相关的上下文信息。但是由于需要穷举各条也许执行的途径,该技术需要解决的工作量随着程序规模的增大而呈指数级别增长。虽然符号执行方法可以被应用于大型程序的分析,其分析结果的可靠性仍依赖于所允许的分析时间和对途径及其数目的选择等方面。 2) 切片分析(Slicing Analysis)。切片分析用于从源程序中抽取对程序中爱好点上的特定变量有影响的语句和谓词,组成新的程序(称作切片),然后通过度析切片来分析源程序的行为[42]。计算程序切片的方法重要有两种:根据数据流方程计算和根据依赖图关系计算。切片分析技术已被广泛应用于程序分析、理解、调试、测试、软件维护等过程[38,39]。 3) 结构分析(Structure Analysis)。结构分析的目的是获得程序的调用关系图(Call Graph),以展示程序中各个函数之间的调用关系。把程序中每个函数当作一个节点,再分析每个函数调用了哪些其他函数,并在存在调用关系的函数间建立一条边,就可以得到调用关系图。调用关系图通常用于辅助开发人员理解程序。对于面向对象程序,程序的结构分析还涉及从程序中获取类图(class diagram)等。除了一些编译器支持结构分析外,目前软件开发过程中的一些工具,例如IBM Rational Rose 等也可以对以开发出的代码进行结构分析。 4) 克隆分析(Clone Analysis)。代码克隆(Code clone)是指软件开发中由于复制、粘贴引起的反复代码现象。研究指出,一般商业软件中存在5%至20%的反复代码[1]。由于克隆代码的普遍性以及克隆代码对代码质量的重要影响,代码克隆相关研究是静态代码分析领域近年来一个十分活跃的研究分支。重要研究内容涉及:克隆代码检测、由代码克隆引起的代码缺陷诊断、通过代码重构来减少代码克隆、克隆代码跟踪、基于代码克隆的源代码演化分析等等。代码克隆分析有十分丰富的实际应用价值,比如缺陷诊断、重构、代码理解、源代码演化分析和代码抄袭检查等等。克隆代码可以分为如下四类:1) 除空格、回车以及注解之外完全相同的代码片段;2) 除空格、回车、注解以及变量名及常量值替换外,语法结构完全相同的代码片段;3) 除空格、回车、注解以及变量名及常量值替换外,语法结构基本相同,但具有少量语句的增长、删除或修改的代码片段;4) 两段或多段代码具有相同或相似的功能,或者说相似的输入、输出条件。其中,最后一类比较特殊,是语义(功能)相似性,其它三类都是文本相似性[5-17]。 2.3. 动态分析 动态分析是通过运营具体程序并获取程序的输出或者内部状态等信息来验证或者发现软件性质的过程。与静态分析相比,动态分析具有如下几方面特点:1)需要运营系统,因此通常要向系统输入具体的数据;2)由于有具体的数据,因此分析结果更精确,但同时只是对于特定输入情况精确,对于其它输入的情况则不能保证。 本文从运营信息的获得途径与获得时机两个方面对动态分析进行介绍。在信息获得的时机上,又根据软件是否已经上线投入使用将软件的动态分析划分为两大类:离线动态测试/验证(Offline Dynamic Testing/Verification)与在线监测(Online Monitoring)。所谓离线动态测试/验证,是指在系统还没有正式上线时对软件进行运营、分析,分析过程中可以随意输入数据,并尽量模拟实际用户的操作。所谓在线监测,是指在系统已经上线后对软件系统进行分析,监测过程中一般不能随意输入数据,所有数据都是真实的。离线动态测试/验证、在线监测与运营信息获取之间的基本关系见图3。 图3 动态分析涉及的重要技术 2.3.1. 运营信息的获取途径 1) 从程序的正常输出中获取信息 每个程序在运营过程中都会产生许多输出信息。有些输出是程序运营中间或者结束时输出的正常结果,有些是一些提醒信息,尚有一些是日记信息。通过将最终得到的实际输出结果与事先设定的盼望输出结果进行对比、分析,就可以得到关于软件的有价值信息。 2) 通过插装代码获取信息 仅仅通过观测程序的正常输出对于了解软件的运营信息往往是不够的。例如,软件运营过程中内部变量的状态信息、某个特定类型的实例信息、模块之间的交互信息等等。这些信息对于发现缺陷,以及定位缺陷特别重要。获得这些内部信息的自然方式是在软件中插装监测代码(Monitoring Code),通过这些监测代码就可以获得相应的信息。重要的监测代码插装方法可以分为如下三类: l 源码插装。这是最自然的插装方式,即在编写应用系统时,在需要监测的地方直接加上监测代码,例如,增长输出信息语句、增长日记语句等等。AOP(Aspect Oriented Programming)技术出现之后,人们发现AOP可以被很好地用于代码插装,以有效地分离系统的业务逻辑与监测逻辑[43]。 l 静态目的码插装。近年来字节码插装技术在Java 社区中十分流行。字节码插装可以在静态直接更改中间代码文献(例如Java 的.class 文献)或在装载时刻进行字节码插装。字节码插装所具有的执行效率高、插装点灵活、应用范围广等特点,使其被广泛应用于AOP等研究领域,并陆续出现了BCEL[64]、Javassist[65]、ASM[66]等多种字节码操纵工具。 l 基于截取器(Interceptor)的获取方式。截取器处在调用者和被调用者之间,可以截获两者之间传递的消息,从而完毕一些特定的解决工作。由于这种获取方式不需要直接修改目的程序,代码侵入性较弱,甚至可以在运营阶段部署,因此得到了越来越广泛的使用。Tomcat服务器、EJB3规范、Spring框架中都有截取器的实现[40]。 3) 通过平台接口获取信息 向目的系统插装监测代码可以很方便地获得内部信息。假如底层的运营平台(操作系统、JVM、中间件、或者数据库管理系统等)提供很好的支持,则许多信息获取起来就更加方便。例如,许多研究人员通过开发特殊的JAVA 虚拟机来获取所需要的监测信息。JPF[50]、QVM[51]等就是典型代表。目前标准的JVM自身也提供了许多供调试、监测的接口,例如 JVMTI[52]等等。 2.3.2. 离线动态测试/验证 离线的动态测试与动态验证都需要在离线的情况下运营程序,并获取、分析运营信息,因此两者有比较密切的联系。不仅如此,为发现更多的软件缺陷,离线动态验证与动态测试都需要仔细准备输入数据。此外,假如将程序的输出与输入之间的关系看作一种约束需求,或者在分析测试结果时也收集日记等内部信息的话,两者就更接近了。从不同之处看,离线动态验证一般比测试收集更多的内部信息、关注更多的约束需求,并且往往运用一些轻权(lightweight)的形式化方法来描述这些需求。从研究内容看,离线动态测试/验证重要关注三个方面的内容:输入数据生成、约束描述、运营轨迹分析。 l 输入数据生成。为了尽也许多地发现潜在的缺陷,在运营程序之前通常需要一方面静态地分析目的程序,根据验证目的(什么功能、什么约束、等等)辅助用户生成和选择输入数据。 l 约束描述。运用形式化方法描述软件约束,以便于分析可以自动进行。目前多数动态验证研究人员运用线性时序逻辑(LTL: Linear Temporal Logic)来描述。 l 运营轨迹分析。程序运营过程中产生的内部、外部数据也许是大量的,需要测试/验证目的对数据进行必要的过滤,然后分析这些数据以推断程序的执行轨迹,并进一步判断程序的执行是否遵循程序的约束。 2.3.3. 在线监测 与离线动态验证相比,在线监测有几个特点:1)系统输入由实际的真实用户与系统拥有者共同决定;2)系统拥有者的输入是受限制的,一些在上线之前可以做的实验(例如:压力测试、安全性测试等)此时不能随意实行,否则就会威胁到系统正常的服务质量;3)监测代码往往就是应用系统的组成部分。这使得在线监测与前面介绍的各种分析都非常的不同:前面介绍的分析技术一般都由特定的分析工具支持,分析工具是一种外部辅助工具,在系统上线后,分析工具就与系统分离了。而在线监测则也许一直随着系统的服务过程,并且也许是在系统上线之后,在不同的维护阶段增长上去的。有研究人员因此提出了面向监测的编程(MOP)[37]。 在分析机制上,在线监测的分析可以采用内联模式(inline)或者外联模式(outline)。在内联监测模式中,监测代码(monitor)与被监测程序运营在相同的空间中,因此执行效率相对要高,且发现异常后响应要快。在外联监测模式中,监测代码运营在独立的运营空间中,比如此外一台机器或者CPU。外联模式效率要低一些,但可以对多项监测内容进行综合解决,因此可以做更进一步的分析。 对于在线系统,假如要监测它,就一定会影响它。假如影响过大,就也许给正常的服务过程带来负面作用。因此,衡量在线监测技术的一个重要指标是监测开销,特别是运营开销。许多监测的时间开销甚至高于程序自身的运营开销。由于在线监测一定会对监测对象的运营产生影响,因此监测的结果也一定是被影响后系统的表现,而不是被监测对象自身的表现。针对这个现象,有些研究人员参照物理学中的测不准原理提出了软件的测不准原理[34]。 需要特别注意的是,在系统上线之后,有价值的监测通常不仅仅针对软件自身,而是针对由软件、硬件组成的服务系统,甚至涉及与服务系统交互的环境(用例图中的 Actor)[35]。例如:客户程序的调用序列、系统的响应时间等等。在这个意义上,在线监测不仅仅是努力发现软件的缺陷,并且关注服务过程的潜在问题(例如:响应时间是否足够小?是否发现可疑的袭击行为?)。因此,随着Web 服务技术、软件作为服务(SaaS:Software as a Service)的推广,在线监测正受到越来越多研究人员的关注[33]。此外,多核解决器的发展,也为监测提供了更多的途径:由于业务逻辑与监测逻辑相对分离,完全可以由不同的核分别进行业务解决与监测解决。 l 对软件内部的监测。对软件内部的监测方法与运营时验证的方法比较接近,上面提到的各种插装技术对于在线监测都合用。不仅如此,对于在线系统,还可以运用在线升级(upgrading)的技术[36],或者动态编织(weaving)技术[41]等将监测代码“在线”地部署到目的系统中,以加强监测的覆盖面;或者从系统中移除监测代码,以减少监测开销。除此之外,尚有许多对实例的监测,例如:负责客户连接对象的实例数目、负责数据库连接的实例数目等等。 l 对外部交互的监测。重要监测对象涉及:来自客户程序的请求消息顺序是否对的?参数值是否在允许的范围内?请求者的权限是否够(与安全相关)?应答消息的参数值是否在允许的范围内?从收到请求消息到发出应答消息的响应时间是否符合规定?管理人员的操作是否合法?等等。 l 对运营环境的监测。对运营环境的监测重要体现为对底层资源的监测,通常是独立于具体应用的监测内容,例如:CPU的使用情况、内存使用情况、网络带宽等等。对于越来越多的嵌入式系统,由于各种资源都有较大的限制,监测就显得更加重要。 2.4. 分析技术的评价 面对种类众多的软件分析技术,人们通常不仅希望能了解它们,还希望对它们进行评价、比较,以在其中选择选择合适自己当前任务的分析技术。事实上,由于这些技术错综复杂,对它们的评价自身也是一个十分值得研究的题目。目前人们比较关注的评价准则有:误报率(False positive rate)、漏报率(False negative rate),精度(Precision)、速度(Speed)、等等。 误报率与漏报率。误报是指当软件不存在某个缺陷时,分析工具报告软件也许存在某个缺陷。大量的误报将导致大量的人工分析工作:人们必须手工判断系统是否真的存在某个缺陷。漏报是指软件中存在某个缺陷,但分析工具没有报告这个缺陷。将报告结果与缺陷的实际情况进行对比,就可以得到具体的量化指标:误报率与漏报率。误报率与漏报率是目前评价分析工具的两个最重要的指标:一个工具的误报率与漏报率越小,说明这个分析工具越好。但实际情况往往是:有的方法在减少误报率方面很有效,但往往同时增长了漏报率;而有的方法在减少漏报率方面很有效,但却抬高了误报率[1]。误报率与漏报率的反面说法分别是查准率(Precision)与查全率(Recall)。一般来说,静态分析可以比较全面地考虑执行途径,因此可以比动态分析发现更多的缺陷,漏报率比动态分析低;但动态分析由于获取了具体的运营信息,因此报出的缺陷一般更为准确,误报率比静态分析低。 精度与速度。为了提高分析的精度,即减少误报率与漏报率,实际的静态分析工具往往综合运用多种分析技术,并需要做一些较进一步的分析,这自然意味着更长的分析时间。因此,分析的精度与分析的速度往往也是一对不可兼得的矛盾体,必须在两者之间进行折中。此外,动态分析由于往往一次只关注少部分的软件性质,因此精度可以更高一些,并且受程序规模的限制较小;而静态分析在程序运营之前就可以实行,因此可以更早地发现问题。 3. 软件分析与质量保障 软件分析的一个重要应用是保障软件质量:通过度析某个软件,查找出其中包含的软件缺陷,就可以让开发人员修改软件,将缺陷修复,从而提高软件质量。ISO9126提出了一个两层、六类的质量模型,涉及:1) 功能性(含:适合性、准确性、互操作性、保密安全性);2) 可靠性(含:成熟性、容错性、易恢复性);3) 易用性分析(含:易理解性、易学性、易操作性、吸引性);4) 效率(含:时间特性、资源运用性);5) 易维护性(含:易分析性、易改变性、稳定性、易测试性);6) 可移植性(含适应性、易安装性、共存性、易替换性)。 本文以ISO9126的分类为基础,从软件分析的角度出发,结合上面的质量属性,归纳出5种相对并列的软件质量属性:对的性(Correctness)、健壮性(Robustness)、安全性(Security)、效率(Efficiency)、易维护性(Maintenance)。当然,这5种属性之间不是完全正交的,它们之间存在着一些不同形式的关联。本节重要介绍如何运用上一节中提到的一些分析技术对这些属性进行分析。特别是,如何运用这些技术发现相应的质量问题。 3.1 软件对的性 “对的性”重要指程序的运营结果是否与预期值相同。假如不相同,则视为结果不对的,该程序包含一个“对的性”错误。对的性的考虑比较单纯,重要是从输入到输出这个函数映射的角度看待计算过程,特别关心输出结果的对的与否,而不考虑输入数据的具体来源与错误输出结果的后果如何。与对的性相对的是健壮性与安全性:对的性考虑的是软件是否按照预先的设定执行,健壮性与安全性则考虑软件是否在一定条件下执行设定之外的事情。 3.2.1 动态测试/验证 动态测试/验证是发现对的性缺陷最有效的手段。对于任何一个稍具规模的软件而言,穷举所有也许输入的测试/验证都是不现实的。因此,对于发现与对的性有关的缺陷而言,测试/验证的关键在于生成有较强揭示错误能力的输入数据,并通过程序的执行最终检测与对的性相关的缺陷。基于程序分析的数据输入生成技术大体可以分为面向途径的测试用例生成[56]和面向目的的测试用例生成[57]。面向途径的测试数据生成是指给定程序的一条执行途径,生成一个恰好执行该条路经的测试用例。面向途径的测试用例生成可以转化为约束求解问题。面向目的的测试用例生成是指,给定测试的某个目的(比如语句覆盖),生成一组可以达成该目的的测试用例。面向目的的测试用例生成通常以面向途径的测试用例生成为基础,其基本思绪是将面向目的的测试用例生成转化成面向途径的测试用例生成甚至直接转化成约束求解问题。多数情况下,一种测试用例生成技术并不仅针对与对的性有关的缺陷,同时也会兼顾与健壮性有关的缺陷。 3.2.2 静态分析 静态分析也是发现与对的性有关缺陷的重要途径。静态分析的基本思绪是建立一些与对的性有关的形式化规约,然后检查软件是否满足这些规约。静态分析可以不针对软件的特定输入发现一类缺陷,因此在很大限度上可以与测试互为补充。 3.2 软件健壮性 “健壮性”重要是指系统是否能控制软件内外客观不良事件的发生,以保持系统的基本服务质量。例如,是否会发生因死锁而导致系统不工作、是否由于内存泄漏而导致系统崩溃、是否因产生数据竞争而导致系统出现错误状态等等。健壮性与对的性之间存在一定的关联:一方面,不对的的输出有也许影响包含软件的系统整体上的健壮性;另一方面,因系统崩溃等因素导致“得不到结果”有时也被认为是“不对的”的一种特殊表现。与“健壮性”比较接近的一个术语是“可靠性”(Reliability)。后者目前被认为重要是指在规定运营环境下、规定期间内,软件无失效运营的概率,并且是评价软件对的性的一种重要途径[55]。由于这个概念与对的性
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服