代码异常定位与处理方法与流程

文档序号:11250799阅读:761来源:国知局

本发明涉及软件调试,特别涉及一种代码异常定位与处理方法。



背景技术:

软件调试在整个软件开发中占据相当大的开销。尽管软件企业在软件调试中已经投入巨资,但软件发行后仍然会被发现有严重的错误。在发行后再对软件错误进行修补,仍会造成严重的经济损失。研究发现,与软件相关的安全事件,其中大都是由在设计或者编码阶段引入的软件错误引起的。但确定一个静态源码检测到的错误是否是一个真实的错误需要花费大量的精力。对于软件错误的自动化检测和修补,现有技术存在以下方案,即不关心待测程序的内部执行情况,随机的产生用例,观察程序输出是否与预期的相符合,但其缺陷是代码覆盖率低,因此其错误检测能力有限。



技术实现要素:

为解决上述现有技术所存在的问题,本发明提出了一种代码异常定位与处理方法,包括:

生成用例,然后向路径约束条件中输入错误约束;

求解新的路径约束条件,产生触发软件错误的用例;

对外部函数进行建模,监控外部函数导致的符号传递;

通过符号传递定位代码错误。

优选地,所述求解新的路径约束条件,产生触发软件错误的用例,进一步包括,检测当前运行路径上的错误的错误约束,在当前运行路径下当错误约束满足时,则触发错误,且得到的解就是保证触发错误的用例。

优选地,所述方法还包括:对待测程序进行监控,当关键指令被执行时,主动在路径约束条件中输入错误约束,并对错误约束进行标记。

优选地,当所述代码错误为数组越限时,检测数组越限错误,追踪符号传递,当有符号作为索引对数组进行访问时,查询当前栈帧范围,获得数组边界,生成违反数组边界要求的错误约束,并输入到当前的路径约束条件中;当新的路径约束条件满足时,则触发数组越限错误;追踪符号从其他变量传递到数组的索引;数组操作识别,即通过逆向分析,将x86架构下的数组操作通过调整编译选项而使得所有的数组操作都编译为基址变址操作;检测数组的合法范围,如果数组操作在合法范围内则是合法的数组操作,否则数组越限,具体包括先进行反汇编,再反编译,获得具有数据结构信息的中间表达形式,再在中间表达形式的基础上进行数组识别,识别数组后使用栈帧范围来作为数组边界的近似。

本发明相比现有技术,具有以下优点:

本发明提出了一种代码异常定位与处理方法,在不降低代码覆盖率的前提下,提高了错误定位效率,优化了代码错误搜索过程。

附图说明

图1是根据本发明实施例的代码异常定位与处理方法的流程图。

具体实施方式

下文与图示本发明原理的附图一起提供对本发明一个或者多个实施例的详细描述。结合这样的实施例描述本发明,但是本发明不限于任何实施例。本发明的范围仅由权利要求书限定,并且本发明涵盖诸多替代、修改和等同物。在下文描述中阐述诸多具体细节以便提供对本发明的透彻理解。出于示例的目的而提供这些细节,并且无这些具体细节中的一些或者所有细节也可以根据权利要求书实现本发明。

本发明的一方面提供了一种代码异常定位与处理方法。图1是根据本发明实施例的代码异常定位与处理方法流程图。

本发明在代码检测系统中,通过产生用例而再现错误,向路径约束条件中输入错误约束,通过求解新的路径约束条件,产生触发软件错误的用例;然后对外部函数进行建模,监控外部函数导致的符号传递,而不增加约束,基于改进的优化路径遍历搜索方法更快地执行到错误路径,从而能够更快地检测到代码错误。

代码检测系统检测当前运行路径上的错误的错误约束,在当前运行路径下当错误约束满足时,则触发错误,且得到的解就是能保证触发错误的用例。代码检测系统对待测程序进行监控,当关键指令被执行时,主动在路径约束条件中输入错误约束,并对错误约束进行标记。

代码检测系统包括多个错误检测单元,分别支持不同类型的错误检测:数组越限、除零错误、空指针引用错误、函数参数错误。数组越限检测单元用于检测数组越限错误,追踪符号传递,当有符号作为索引对数组进行访问时,查询当前栈帧范围,获得数组边界,生成违反数组边界要求的错误约束,并输入到当前的路径约束条件中;当新的路径约束条件满足时,则触发数组越限错误。该数组越限检测单元还用于符号索引追踪,即追踪符号从其他变量传递到数组的索引;数组操作识别,即通过逆向分析,将x86架构下的数组操作通过调整编译选项而使得所有的数组操作都编译为基址变址操作;和数组边界检测,即检测数组的合法范围,如果数组操作在合法范围内则是合法的数组操作,否则数组越限,具体包括先进行反汇编,再反编译,获得具有数据结构信息的中间表达形式,再在中间表达形式的基础上进行数组识别,识别数组后使用栈帧范围来作为数组边界的近似。除零错误检测单元用于检测除零错误,将div(无符号除)和idiv(带符号除)两种指令视为关键指令,当符号作为除数时,生成错误约束,并输入到路径约束条件中,最后通过求解新路径约束条件,获得可以触发除零错误的用例。代码检测系统。空指针引用错误检测单元用于检测空指针引用错误。当一个符号作为地址被引用时,判断地址是否与符号有关,并输入到路径约束条件中,通过求解新路径约束条件,获得可以触发空指针引用错误的用例。函数参数错误检测单元用于并对需要检测的函数插桩,当关键函数被调用且函数参数与符号相关时则生成错误约束,并输入到路径约束条件中。为了对关键函数进行插桩,代码检测系统利用插桩工具pin对导出关键函数的映像文件进行插桩,当映像文件加载时,搜索映像文件中关键函数的位置,再对关键函数插桩。

当待测程序调用外部函数时,代码检测系统根据外部函数的地址,利用插桩工具提供的api获得外部函数名。然后,根据外部函数的函数名判断该函数是否有对应的函数模型,如果没有,则实际执行该函数。如果有对应的函数模型,判断函数的参数是否与符号相关,如果函数的参数与符号相关,则执行函数模型,追踪符号传递,随后进行实际执行。

在路径遍历搜索过程中,首先接受初始用例作为其参数。初始用例的边界设置为0,表明执行初始用例产生的路径约束条件从深度0开始都被否定,以产生新的路径约束条件。将初始用例加入到一个工作列表中;实际执行待测程序,其输入为初始用例,检测初始用例能否触发错误。当工作列表不为空时,则进入顶层循环的动态符号执行;依据是用例的分值,从工作列表中选择一个用例作为当前动态符号执行的输入,分值越高代表优先级越高;对待测程序进行动态符号执行,并生成新的用例集合。对集合中每一个用例进行实际执行,检测是否能够触发待测程序的错误,并对每个新用例进行评分。

为了检测内存函数错误,代码检测系统首先将所有的输入标记为可疑点,表示所有的输入都是不可信的,然后追踪可疑点传递,当可疑点数据作为源操作数的时候,将指令的目的操作数也标记为可疑点。当可疑点数据传递到内存函数时,即可疑点数据作为内存函数的参数时,则找到了内存函数错误。

在可疑点的数据结构上,采用一个连续的内存空间。给定一个虚拟地址addr,使用这个地址addr,找到可疑点数据结构的字节位置,再找到字节中的位偏移。如果这1位为1,表示对应的地址addr是可疑点数据,如果是0则表示该地址不是可疑点数据。然后对可疑点传递进行追踪。具体包括:注册一个初始化回调函数,对追踪可疑点传递所需要的临时数据结构进行初始化。该临时数据结构存储内存地址和宽度信息、寄存器、指令操作码、指令类型。判断是否是内存读取操作,如果是则根据读取的内存地址和内存操作数的大小,而将这些信息存储到临时数据结构中;判断是否是内存修改操作,如果是则根据修改的内存地址和内存操作数的大小而将这些信息存储到临时数据结构中。获得读取的寄存器。将该寄存器信息存储到临时数据结构中。将该寄存器信息存储到临时数据结构中。将指令类型和指令操作码信息存储到临时数据结构中。到临时数据结构中查找所有被读取的寄存器和内存地址,然后利用上述可疑点数据结构中查询是否是可疑点。如果不是,则将记录在临时数据结构中的那些被修改的寄存器和内存地址的可疑点信息全部删除。如果有任何一个寄存器或者内存地址是可疑点,则将记录在临时数据结构里的那些被修改的寄存器和内存地址全都标记为可疑点。

对于空指针引用错误检测,本发明还提供了一种可选的方式:

步骤1:读取源文件,对其进行词法分析和语法分析,利用辅助工具生成应用的语法树,根据所述语法树生成反映应用控制结构的控制流图,并根据所述语法树创建应用的符号表系统与类型系统,基于语法树识别出应用的全部可定位表达式,具体包括:基于语法树识别出应用的所有定义的符号以及所有使用的可定位表达式;识别所有定义的函数,并将识别的函数作为一个符号加入到相应作用域中;识别所有定义的结构体与联合;并将识别出的结构体与联合作为一个符号加入到相应作用域中;识别出结构体与联合的成员,并加入到相应作用域中;识别所有定义的变量;其中,变量的类型为指针时,将变量作为一个指针类型符号添加到相应的作用域中,将指针的引用作为一个待识别的变量;变量的类型为数组时,将变量作为一个数组类型符号添加到相应的作用域中,将数组的每一个成员作为一个待识别的变量;变量的类型为结构体或联合时,将变量作为一个结构体与联合类型符号添加到相应的作用域中,将结构体与联合的每一个成员作为一个待识别的变量;否则,将变量作为一个基本类型符号,添加到相应的作用域中。基于语法树识别出应用的所有使用的可定位表达式,包括从语法树上的后缀表达式节点识别所有使用的后缀表达式;从语法树上的一元表达式节点识别所有使用的指针引用表达式。

对于识别出的可定位表达式,通过类型推导规则推导其类型。对于声明的标志符变量,根据其声明可知其类型。对于复杂数据类型的变量:(1)如果是数组,可知其元素的类型;(2)如果是指针,可知其指向的表达式的类型;(3)如果是结构体,可知其每个域成员的类型;对于不能通过声明识别的表达式,通过类型推导规则推导出其类型。

步骤2:根据控制流图产生时的节点号顺序,取控制流图中的下一个节点作为当前节点,如果所述当前节点为最后一个节点,则结束遍历;所述生成函数摘要,对所述当前节点上第一次出现的变量,用基于区域的四元模型<variable,region,expression,domain>对所述变量进行建模,并根据所述变量的类型进行初始操作,包括:设置初始的区间值;若变量的类型是指针,设置其指向集合为空;其中,variable为被建模的所述变量,region为所述变量分配的抽象内存区域,expression为符号表达式,domain为取值区间;对所述当前节点的前驱节点上出现的除作用域的指针之外的每一个指针,求其在所述当前节点的所有前驱节点上的指向集合的并集,得到该指针在所述当前节点上的初始指向集合;其中,所述作用域为符号表系统中的作用域,用于存储识别出的各类符号;对所述当前节点的前驱节点上出现的除作用域的变量之外的每一个变量,求其在所述当前节点的所有前驱节点上的取值区间或区间集的并集,得到该变量在所述当前节点上的初始取值区间或初始区间集,然后判断在所述当前节点上是否存在某个变量的初始取值区间或初始区间集为空,若存在,则标记该节点为矛盾节点;若不存在,则根据所述当前节点所对应的语句类型,对该节点上每个已获得初始指向集合的指针进行相应的指针分析,对该节点上的每个已获得初始区间值或初始区间集的变量进行相应的区间运算。其中,当变量是基本类型时,用基于区域的四元模型对其进行建模,根据其具体类型设置初始区间;变量是数组元素时,建立数组的region与该变量region的父子层次关系;变量是结构体或联合类型时,建立结构体或联合的region与该变量的region的父子层次关系;变量是指针类型时,设置其指向集合为空,设置其初始状态为unsure。

若所述当前节点所对应的语句类型为赋值语句,将指向集合的每一个抽象内存区域,其取值区间为变量当前的取值区间与右端表达式取值区间的并集;如果指向集合的抽象内存区域类型为指针类型,则每一个抽象内存区域的指向集合为当前指向集合与右端表达式指向集合的并集;若所述当前节点所对应的语句类型为条件语句,将该变量的每个成员作为一个被赋值变量,将右侧表达式中的每一个对应的成员作为为该成员赋值的右侧表达式,如果被赋值变量的类型为基本类型,则根据被赋值变量的类型及右端表达式计算该赋值语句中表达式的取值区间,并将所述被赋值变量的取值区间重置为该新计算出的表达式的取值区间;若所述当前节点所对应的语句类型为条件判断语句,则对该节点所关联的每一指针取初始的可能指向集后,分析该节点所关联的每一指针在所述条件判断语句中指向的可能集合和必然集合;对该节点所关联的每一变量取初始的可能集后,计算该节点所关联的每一变量在所述条件判断语句中的取值的可能集和必然集,进而得到该节点所对应的控制流图中真假分支上的所述变量取值情况;

所述生成函数摘要具体包括:生成函数摘要的前置约束条件;识别出需要被约束的、类型为指针的函数参数与全局变量;计算出被约束指针的弱约束条件。分析函数调用引起控制流发生改变的情况;计算函数的返回值。分析函数调用对指针类型形参与指针类型全局变量的指向关系与状态的更新;分析函数调用对全局变量的数据流更新。

步骤3:根据所述函数摘要以及语法树识别出全部的指针引用以及被引用的指针,并对每个被引用的指针创建空指针引用缺陷状态机实例;在语法树的一元表达式节点上识别出指针引用,以及被引用的指针;在语法树的后缀表达式节点上识别出的指针引用,以及被引用的指针;在语法树的一元表达式节点上识别出函数调用表达式;如果函数调用表达式对应的被调用函数有函数摘要时,则获取函数摘要的前置约束条件,以及所述前置约束条件中全部被约束变量,将与所述被约束变量对应的实参或全局变量作为被引用的指针;如果函数调用表达式对应的被调用函数没有函数摘要时,将传递给被调用函数的所有指针类型参数作为被引用的指针。

步骤4:基于控制流图运行空指针引用缺陷状态机实例,在控制流图的每个节点上,根据区间运算、指针分析的结果对每个缺陷状态机实例进行状态迁移,确定安全指针引用集合、空指针引用集合、不确定的指针引用集合。

其中,赋值表达式的指针分析与区间运算过程具体包括:

判断等号左侧表达式的类型,若等号左侧表达式为指针解引用,则根据等号右侧不同表达式信息进行区间运算与指针分析;若等号左侧表达式为指针变量,则根据等号右侧不同表达式信息进行区间运算与指针分析;若等号左侧表达式为复杂数据结构类型,根据等号右侧不同表达式信息进行区间运算与指针分析;否则,将等号左侧表达式的类型为基本数据类型,根据等号右侧不同表达式信息进行区间运算与指针分析。

当左侧表达式的类型为基本数据类型时,如果右侧是指针解引用,则获得右侧被引用指针的指向集合,求得指向集合所指向的抽象内存区域的符号取值的并集,将左侧变量的抽象内存区域的符号取值更新为所得并集;否则,将左侧变量的抽象内存区域的符号取值更新为右侧表达式的符号取值。当左侧表达式的类型为被引用指针时,获得左侧被引用指针的指向集合,获得指向集合对应的抽象内存区域集合;如果抽象内存区域均已被处理,结束对左侧是指针解引用的赋值语句的处理;否则,取抽象内存区域集合中一个未被处理的抽象内存区域,然后判断左侧表达式类型是否为复杂数据类型,如果是,对抽象内存区域根据等号右侧不同表达式信息进行区间运算,如果不是,对抽象内存区域根据等号右侧不同表达式信息进行区间运算与指针分析。左侧表达式的类型为指针变量时,将左侧指针变量对应的抽象内存区域的指向集合置为空;判断右侧表达式是否为变量地址,若为变量地址,将右侧地址变量对应的抽象内存区域添加到左侧指针的抽象内存区域的指向集合,左侧指针的抽象内存区域的取值为非空;若不为变量地址,分析右侧指针表达式的指向集合与取值,将右侧表达式的指向集合赋予给左侧指针的抽象内存区域的指向集合,将右侧表达式的取值赋值给左侧指针的抽象内存区域的取值。

函数调用语句的指针分析与区间运算过程具体包括:获得被调用函数的函数摘要;获得函数摘要的后置约束条件,获得后置约束条件中产生了副作用的引用类型的函数参数与全局变量;对产生了副作用的引用类型的函数参数与全局变量,基于后置约束条件更新其区间取值与指向信息。

在进行过程间分析创建函数摘要时,考虑到全部的被分析函数作用域内的变量包括顶级变量与成员变量。同时考虑到每个被约束变量的弱约束条件以。因此函数摘要的前置约束条件约束的变量是被解引用的指针类型的函数参数与全局变量、以及它们是指针类型的成员;函数摘要的后置约束条件是被该函数副作用影响的对指针类型的参数与全局变量及它们的成员;函数摘要的特征信息包括函数的返回值、控制流终止信息。

在面向对象程序中,对象是面向对象程序运行时的基本活动单位。因此本发明另一方面对每个类容器中的语句结合所属对象的可疑率信息,区分不同类中具有相同覆盖信息语句的可疑率,首先提取对象可疑率信息的提取方法;对象可疑率信息与语句频率信息的结合方法。

在可疑率提取过程中,首先执行多条失败用例和多条成功用例,搜集每个对象的过程调用执行轨迹;然后,把每个对象的过程调用执行轨迹划分为窗口大小为3的过程调用序列,根据用例执行信息,生成过程调用序列频率信息。使用四元组(aep,anp,aef,anf)表示过程调用序列频率信息,其中aep,anp分别表示成功用例执行和未执行过程调用序列的数量,aef,anf分别表示失败用例执行和未执行过程调用序列的数量。

然后,基于过程调用序列频率信息以及搜集到的调试执行结果向量,设计度量公式:

其中pass(p)=aep/(anp+aep)表示成功用例执行过程调用序列p的百分比,fail(p)=aef/(anf+aef)表示失败用例执行过程调用序列p的百分比。

然后,利用上述计算的过程调用序列可疑率量化对象的可疑率信息:搜集每个对象的过程调用序列集合,把属于同一个类的所有对象的过程调用序列集合合并为一个类的过程调用序列集合,该集合描述了该类在程序中的执行行为;然后,把类的过程调用序列集合s(c)的平均可疑率作为该对象的可疑率w(c):

w(c)=∑p∈s(c)w(p)/t;

其中t=为s(c)中元素的个数。

把每条语句按照基于失败用例执行数目的分组策略分成若干组。通过分组策略,防止排名靠后的可疑语句结合对象可疑率信息后排名高于错误语句。

根据分组策略,假设将可疑语句分为1-n组,标记为g0,g1,g2,……,gn-1。gi中的下标i表示有i个失败用例执行了gi组内的可疑语句。每条可疑语句只包含在一个组内,可疑语句和组具有多对一的映射关系。给定语句s,算法的可疑率计算方式如下。

在上述公式中,tf代表失败用例的总数,c(s)表示包含语句s的类。w()表示相应对象的可疑率,m(s)表示由频率错误定位过程计算得到的语句s可疑率;并且当s∈gi时,ti=1;否则ti=0。

在结合函数嵌套路径信息的错误定位中,将函数嵌套路径信息与程序频率信息相结合,然后提供失效相关的函数嵌套路径信息作为上下文信息,缓解程序频率信息的局限性对错误定位效果的影响。

给定被测程序和相应的用例集,首先搜集函数嵌套边剖面信息,构建加权的函数嵌套图;然后,利用过程间函数嵌套路径遍历搜索算法搜索错误语句,对可疑语句在排序中的审查顺序进行重新定义,并利用函数嵌套路径信息将审查的语句关联起来。

给定被测程序以及相应的用例集,静态分析源代码,获得相应的函数嵌套图。在函数嵌套图中,每个节点表示—个函数,每条边对一个函数嵌套关系。插桩源代码,执行相应的用例集,搜集函数嵌套剖面信息,即每条函数嵌套边的执行信息。根据函数嵌套剖面信息,计算函数嵌套图中每条边的权重,建立加权的函数嵌套图。基于加权的函数嵌套图,按照预定义遍历算法搜索错误,并记录搜索错误过程中要检测的可疑语句以及相应的函数嵌套路径信息。将搜索过程中要审查的可疑语句进行定位错误。

在已有函数嵌套图g(p)=<m,e>的基础上,eij表示从mi到mj的嵌套关系。函数嵌套边执行剖面信息构建加权的函数嵌套图。在加权函数嵌套图中,每条函数嵌套边具有一个权重,该权重表示相邻两个函数节点关系的紧密程度。如果用例t执行了eij对应的函数嵌套,则记为eij被用例t所覆盖。给定用例集t=tp∪tf其中表示tp成功调试用集,tf表示失败用例集。ep(eij)={θ(eij,t1),θ(eij,t2),…θ(eij,tn)}表示调用边eij的执行剖面信息。当用例tk覆盖了eij时,θ(eij,tk)=1;反之,θ(eij,tk)=0。成功用例集tp和失败用例集tf关于eij执行剖面信息分别记为epp(eij)和epf(eij),通过以下方法分别计算eij关于成功用例集和失败用例集的执行次数esp(eij)和esf(eij):

采用esp(eij)和esf(eij)的平均值作为每条调用边eij的权值:

wt(eij)=(esp(eij)和esf(eij))/2

在基于基于加权的函数嵌套路径的搜索时,通过遍历加权函数嵌套图搜索错误语句,同时搜集相关的函数嵌套路径信息作为上下文帮助理解错误;重新定义中语句的排序,将独立的不相关的语句进行关联。

1.首先按照原排序选择具有高可疑率的语句,或者属于同一个函数的具有相同可疑率的语句,将包含这些语句的函数入栈,并作为加权函数嵌套图中搜索的起点。

2.基于搜索起始节点,首先深度优先搜索它的父节点,最多遍历三层深度。在遍历每层函数节点时,在该函数中具有较高可疑率的语句将按照顺序进行审查,如果检测的语句中包含错误语句,则遍历算法停止;否则把该函数节点入栈,并选择具有最大权重的邻接边作为要遍历的下一条边。当没有边可以遍历或者深度己经超过3时,回溯到栈中存放的上一个节点重复上述遍历的过程。

3.当遍历完该节点的父节点,并未搜索到错误语句,重复步骤2中的搜索过程深度优先遍历它的子节点。

4.记录这一轮遍历错误语句过程中需要审查的代码,以及相应函数嵌套路径信息。如果遍历完相关函数节点未发现错误语句,则从步骤1开始继续这个过程,直到检查到错误语句为止。

对于步骤2和步骤3,在选择下一条要遍历的函数嵌套边以及每个函数节点所要审查的可疑语句时,使用了如下启发式过程:

在每次选择下一个函数节点进行遍历时,应选择未遍历的函数嵌套边,以及至少一条失败用例执行了该函数嵌套边,而且该函数嵌套边具有最大的权值。在遍历函数节点所包含的可疑语句时,只记录如下可疑语句:在当前函数节点里未检査,而且具有最高可疑率;在排序到这一轮遍历的起始节点所记录语句的排序距离不超过所有语句数量的10%。

综上所述,本发明提出了一种代码异常定位与处理方法,在不降低代码覆盖率的前提下,提高了错误定位效率,优化了代码错误搜索过程。

显然,本领域的技术人员应该理解,上述的本发明的各模块或各步骤可以用通用的计算系统来实现,它们可以集中在单个的计算系统上,或者分布在多个计算系统所组成的网络上,可选地,它们可以用计算系统可执行的程序代码来实现,从而,可以将它们存储在存储系统中由计算系统来执行。这样,本发明不限制于任何特定的硬件和软件结合。

应当理解的是,本发明的上述具体实施方式仅仅用于示例性说明或解释本发明的原理,而不构成对本发明的限制。因此,在不偏离本发明的精神和范围的情况下所做的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。此外,本发明所附权利要求旨在涵盖落入所附权利要求范围和边界、或者这种范围和边界的等同形式内的全部变化和修改例。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1