程序设计中内存操作错误的识别方法

文档序号:6413818阅读:315来源:国知局
专利名称:程序设计中内存操作错误的识别方法
技术领域
本发明涉及计算机软件测试技术,具体涉及一种用于检测程序设计中错误内存操作的软件测试方法,更具体地说,涉及一种C/C++程序设计中内存操作错误的识别方法。
作为系统程序设计语言的C/C++是一种高度灵活的语言,也正是这种灵活性为程序的正确编写带来极大困难,貌似正确的程序常常因为错误的指针和数组操作而导致系统崩溃。国外已有类似的测试工具,如Purify、Visionsoft和Smartheap等,其功能各有侧重。Visionsoft和smartheap在检测错误的内存操作方面功能很弱,因为它不能对被测源程序进行有效的插装。上述测试工具Purify能检测出不少的内存错误操作,但它有一个严重缺陷,即它没有建立内存块和指针间的关联,它只能判断指针的引用是否指向非法内存,而不知道它是否已经指向了另一块合法内存,这是一个严重错误。例如,如图所示,内存块1和内存块2是purify所登记的两块内存,它们的首址和尺寸分别是(0X1000,4)、(0X1008,8)。现在有一指针p,程序将内存块1的首址赋给了它,即p指向了内存块1,现在有一关于指针p的引用*(p+10),它已经越出了内存块1而到了内存块2的内部,由于purify认为内存块2是一块合法的内存,它不会报告这个错误。其根本原因在于purify没有为指针和内存块建立关联,它不知道一个指针应该指向哪一块内存。
本发明的目的是提出一种新的识别程序设计中内存操作错误的方法,它可以针对purify类软件在指针越界检查方面存在的上述弱点,不仅能检测purify类软件所能检测的所有错误,还能准确地判断指针的引用是否越出了它所指向的内存块。对于上例中的指针越界错,它能很容易地作出判断。
本发明的目的是这样实现的,构造一种识别程序设计中内存操作错误的方法包括以下步骤由插装程序对被测试源程序进行分析插装,对被插装后被测源程序进行编译产生可执行的被测程序,运行该可执行程序后产生错误日志,最后由错误信息浏览装置对错误日志信息进行处理,其特征在于所述插装程序是这样对被测试源程序进行分析插装的所述对源程序进行插装的步骤是基于包含有指针句柄表和颜色表的插装库进行的,所述指针句柄表为每个指针项记录其指针标示和内存块句柄,所述颜色表为每一个内存块项记录内存块标示、属性和指向它的指针句柄,所述的对源程序进行插装的步骤包括打开源程序文件并对每一语句进行分析,分别作如下处理对语句中包含有动态内存、变量和字符串常量的内存块时,插入登记内存块的语句;对分析中出现指针赋值语句时,插入登记指针并建立与内存块间关系的语句;对分析中出现有数组和表达式语句时,插入对数组及表达式进行检查的语句。
按照本发明提供的方法,其特征在于,所述插入登记内存块的语句包括对动态内存块,接管动态内存分配函数,在新的动态内存分配函数中首先调用系统提供的被替换前的分配函数来完成实际的内存分配工作,然后调用插装库里的相应函数来登记刚分配的动态内存;对字符串常量,用一函数将被测程序中所出现的字符串常量“包”起来,在“包”它的函数中调用插装库中的相应函数来登记这个字符串常量;对变量,记住每一个变量的定义,并且在之后的适当位置插入登记这些变量的语句。
按照本发明提供的方法,其特征在于,所述插入登记指针并建立与内存块间关系的语句是指在所有找到的为指针赋值的表达式的后面,插入登记指针和建立联系的语句,如果为指针赋值的表达式中“=”右表达式的最外层最终可归结为一个指针经过有限次的‘+’、‘-’运算的结果,则将“=”左指针和找到的这个指针指向同一块内存;否则,用右表达式的值在颜色表中进行匹配,如果它的值落在某一块内存之中,则认为“=”之左指针指向这块内存,在不能区分以上两种情况时,按第二种情况处理。
按照本发明提供的方法,其特征在于,所述插入对数组及表达式进行检查的语句是指在每一个数组表达式和指针表达式前面,按由内到外的顺序逐层检查,插入相应代码,以便可根据所述指针句柄表与颜色表,准确地检查出程序中指针越界和数组越界错误操作。
实施本发明提供的程序设计中内存操作错误的识别方法,可以有效地检测出诸如C/C++编程语言所编制程序中的如下一些错误1)引用未初始化的指针;2)数组引用越界;3)指针引用越界;4)读未初始化的动态内存;5)释放无效的内存块;6)动态内存分配而未释放(内存泄漏)。本发明提供的识别方法并不局限于某一产品,也不受运行平台的限制,是一个通用的测试手段。利用本发明的方法,可以大大提高程序可靠性,改善测试效率和程序质量,并可大大降低在软件测试方面的开销。
结合附图和实施例,进一步说明本发明的特点,附图中

图1为用于说明发生内存操作错误时的内存组织示意图;图2是说明本发明中指针句柄表与颜色表之间关系的示意图;图3是利用本发明的方法识别程序设计中内存操作错误的整体流程示意图;图4是利用本发明的方法进行程序设计中内存操作错误识别的插装程序的流程示意图;图5是利用本发明的方法对数组表达式进行识别处理的流程示意图;图6是利用本发明的方法对指针表达式进行识别处理的流程示意图。
为进一步说明本发明的方法,将其中涉及的基本概念说明如下1)插装对于给定的源程序,按预定的规则插入代码和改装程序,这个过程叫插装。由C/C++语言的特性决定了必须插装被测源程序才能对它进行比较完善和准确地检查。
2)插装库将同被测程序一起运行的函数库,它提供了一系列的服务,如登记内存块、登记指针、指针表达式检查、数组表达式检查等。这些服务都是以C函数的形式存在,通过调用这些函数来获得服务。
3)插装规范穷尽所有需要插装的句型,制定相应的插装规则。这些规则的集合就是插装规范。每条规则包括两部分的内容什么情况下需要这种插装;插装什么内容。
4)插装程序按给定插装规范插装被测源程序。它具体实现了插装规范中的每条规则。
5)指针句柄表和颜色表用来明确每个指针所指向的内存块,以及一块内存为哪些指针所指的两张表,它完整的描述了每一指针和内存块间的关系。这两张表的结构已定义在插装库中,插装库还提供相应的服务来操作这两张表,插装程序在需要的时候将调用这些服务的语句插入到被测源程序中,被测程序在运行时根据这些语句动态地维护这两张表。
指针句柄表是指针项的集合,颜色表是内存块项的集合。如图2所示,指针句柄表201中的每一项记录每一个指针的信息,包含有它所指向的内存块在颜色表中的句柄,上例中指针项1、2、n中的内存块句柄分别为1、1、2。
颜色表202记录每一合法内存块(动态内存、变量、字符串常量)信息,其中包含有指向它的指针在指针句柄表中的句柄,上例中,内存块项1、2、n中存储的指向它的指针的句柄分别为{1,2}、{n}、Φ。
内存块退出作用域时,将在颜色表中找到它所对应的内存块项,由其所记录的指向它的指针的句柄,在指针句柄表中找到对应的指针项,将这些指针项中的内存块句柄置空。
指针标示是一个地址,即指针所在的地址,对一个给定的指针pointer,它的标示为&pointer;内存块标示也是一个地址,是这块内存的首址。上例中我们只是简单的取标示为1,2,......等。
图3示出了利用本发明的方法识别程序设计中内存操作错误的整体流程示意图。如图所示,先在方框302中对被测源程序301进行分析并按预定的规则进行插装,将经过插装的源程序303在框304由用户提供的编译程序进行编译,形成可执行的被测程序305,并在框306中对可执行的被测程序305进行执行,在执行过程中,产生错误日志(框307),最后在框308中调用错误信息浏览器浏览错误。由于被测源程序(框301)已插入了利用本发明方法提供的代码,并按要求进行了改装(框302),所以能够动态地跟踪检测并浏览到原被测程序中存在的内存操作错误。
如前所述,本发明的关键在于通过插装代码,能够动态地跟踪被测程序,以检查程序错误。因此插入的内容(称之为插装库)和插装规范将在实施本发明的方法中显得尤为重要,也是本发明方法区别于和优于现有技术的关键之所在。
只有将调用插装库的语句正确插入被测程序,插装库才有价值,插装规范决定了插装库的内容,插装规范是整个方法及其实施的核心。插装程序严格按照插装规范分析并插装被测程序,它所插入的内容是调用插装库所提供的服务的语句。插入的语句在被测程序运行时会完成这样两大部分的工作维持指针句柄表和颜色表以及它们之间的关系;对指针表达式和数组表达式进行检查。图4示出了利用本发明的方法进行程序设计中内存操作错误识别的插装程序的流程。如图4所示,在进行的准备操作401后,在框402打开被测源程序文件,在判定框403中判定是否文件结束,如是文件结束,则转到结束框409,如不是文件结束,则在框404中从被测源程序中读一语句到缓冲区S,再在分析框405中对S中内容进行分析,并分别不同情况进行相应处理,如分析出是动态内存、变量和字符串常量,则在框406中进行插入登记内存块的语句的操作;如分析出程序中出现指针赋值语句,则在框407中进行插入登记指针并建立与内存块间关系的语句的操作;如分析出语句中包含数组表达式或指针表达式语句,则在框408中插入对数组和指针表达式进行检查的语句;在完成框406、407和408中的操作后,重新转到框403进行是否为文件结束的判定,如此循环,直到读到文件结束,程序终止于框409。
下面结合图4中的三个主要处理过程插入登记内存块的语句(框406),插入登记指针并建立它与内存块间关系的语句(框407);插入对数组和指针表达式进行检查的语句(框408),进一步说明本发明的方法中所采用的插装规范。<1>插入登记内存块的语句此处只考虑登记这样几类内存块动态内存、变量和字符串常量。分别描述如下动态内存块的登记规范接管动态内存分配函数,在新的动态内存分配函数中首先调用系统提供的被替换前的分配函数来完成实际的内存分配工作,然后调用插装库里的相应函数来登记刚分配的动态内存。
字符串常量登记规范用一函数将被测程序中所出现的字符串常量“包”起来,在“包”它的函数中调用插装库中的相应函数来登记这个字符串常量。
变量登记规范记住每一个变量的定义,并且在之后的适当位置插入登记这些变量的语句。适当的位置示被测程序是C还是C++而定,对于C程序,将在这块语句中所有变量定义之后和第一条非变量定义语句之前插入登记这些变量的代码;对于C++程序,可以在紧跟着变量的定义之后插入代码来登记这些变量。<2>插入登记指针并建立它与内存块间关系的语句本发明的方法只有在分析出程序包含有指针赋值语句时才登记该指针,登记指针的同时也就把颜色表中的某些内存块和这个指针联系起来了。具体地,将找到所有的为指针赋值的表达式,在之后插入登记指针和建立联系的语句。
在为指针和内存块建立联系时,我们采取了这样一种策略。即找到每一为指针赋值的表达式,根据“=”右表达式的结构,将其区分为两种情况,分别作不同的处理。如果右表达式的最外层最终可归结为一个指针经过有限次的‘+’、‘-’运算的结果,我们将认为“=”左指针和找到的这个指针指向同一块内存。否则,我们将用右表达式的值在颜色表中进行匹配,如果它的值落在某一块内存之中,则认为“=”之左指针指向这块内存。在不能区分以上两种情况时,我们将按第二种情况处理。<3>插入对数组和指针表达式进行检查的语句指针表达式和数组表达式总可表达为这样两种形式p[exprl][expr2]…[exprn]及*(…*(*(p+expr1)+expr2)+exprn)。其中expr1,expr2,…exprn又可能是指针表达式或数组表达式,这是嵌套的表示。
本发明的方法对于被测程序中出现的每一个数组表达式和指针表达式,都将在它的前面,按由内到外的顺序,插入相应代码,一层一层的检查。
一旦插装程序将相应的检测语句插入到被测程序中,当被测程序运行时,这些语句将根据指针句柄表与颜色表,准确地检查出程序中错误的内存操作,错误的内存操主要包括指针越界和数组越界。
下面讨论插入的这些语句是如何对数组表达式和指针表达式进行检查的。
图5示出了对数组表达式进行识别处理的具体流程。对数组表达式检查是这样进行的,如图5所示,插装库在收到对数组表达式进行检查的请求后,首先在框501中进行准备,在框502中进行id和addr的赋值,在框503把数组的地址作为关键字在颜色表中进行查找,在框504中进行判定,如找到内存块,则进到框505,根据内存块属性(首址、尺寸)在框506中判断判断这个数组引用addr是否越界,如越界就在框507记录错误信息,如没有越界,则进到结束框508。
图6示出了对指针表达式进行识别处理的流程。如图6所示,插装库在收到对指针表达式进行检查的请求后,从开始框601开始,在框602中对id和addr进行赋值,然后在框603中,把指针地址id作为关键字,在指针句柄表中查找其对应项pointer,在框604中判定是否找到,如未找到,则进到框609,记录错误信息;如已找到,则在框605中,以框603中找到的poniter作为内存块句柄,查找颜色表中对应的内存块项mem,在框606中,如未找到内存开项,则进到框609,记录错误信息;如已找到,则在框607,根据此内存块项中存储的内存块属性(首址、尺寸等)来判断这个指针表达式是否越界,如在框608中判定是发生越界,则进到框609,记录错误信息;如未发生越界,则进到结束框610,在框609记录完错误信息后,也转到结束框610。<4>其它规范对于特定的句型,如while、do-while、for、switch等语句,插装规范将对它进行改装,以满足我们上述登记和检查的需要。
作为附带工作,可以插入代码完成诸如读未初始化的动态内存、释放无效的内存块、动态内存分配而未释放等检查。
最后介绍本发明方法的一个具体的实施案例利用本发明的方法构造的测试工具Clearify是一个与产品和运行平台无关的测试工具,只要求所在平台提供标准C/C++编译器即可。利用该测试工具Clearify我们对一个用C/C++编程的大型交换机软件进行的内存操作错误的识别,其使用方法如下将被测软件(或模块)的makefile文件中的宏CC更改为CC=clearify hc386 hc386,执行命令make编译被测软件,将得到的可执行程序输入到主机或仿真环境中,运行,最后调用Clearify提供的错误信息浏览器定位错误。通常,在C/C++程序中,内存操作错误在所有可能的错误中占有最大比重,尤其是对于数十万行的大型软件。一个可以预见的效果是交换机将因此而运行得更加稳定,至少我们可以排除这种错误。
权利要求
1.一种识别程序设计中内存操作错误的方法,包括以下步骤对源程序进行插装,编译并运行插装后的程序,从运行产生的错误日志取得出错信息,其特征在于所述对源程序进行插装的步骤是基于包含有指针句柄表和颜色表的插装库进行的,所述指针句柄表为每个指针项记录其指针标示和内存块句柄,所述颜色表为每一个内存块项记录内存块标示、属性和指向它的指针句柄,所述的对源程序进行插装的步骤包括打开源程序文件并对每一语句进行分析,分别作如下处理对语句中包含有动态内存、变量和字符串常量的内存块时,插入登记内存块的语句;对分析中出现指针赋值语句时,插入登记指针并建立与内存块间关系的语句;对分析中出现有数组和表达式语句时,插入对数组及表达式进行检查的语句。
2.根据权利要求1所述的方法,其特征在于,所述插入登记内存块的语句包括对动态内存块,接管动态内存分配函数,在新的动态内存分配函数中首先调用系统提供的被替换前的分配函数来完成实际的内存分配工作,然后调用插装库里的相应函数来登记刚分配的动态内存;对字符串常量,用一函数将被测程序中所出现的字符串常量“包”起来,在“包”它的函数中调用插装库中的相应函数来登记这个字符串常量;对变量,记住每一个变量的定义,并且在之后的适当位置插入登记这些变量的语句。
3.根据权利要求1所述的方法,其特征在于,所述插入登记指针并建立与内存块间关系的语句是指在所有找到的为指针赋值的表达式的后面,插入登记指针和建立联系的语句,如果为指针赋值的表达式中“=”右表达式的最外层最终可归结为一个指针经过有限次的‘+’、‘-’运算的结果,则将“=”左指针和找到的这个指针指向同一块内存;否则,用右表达式的值在颜色表中进行匹配,如果它的值落在某一块内存之中,则认为“=”之左指针指向这块内存,在不能区分以上两种情况时,按第二种情况处理。
4.根据权利要求1所述的方法,其特征在于,所述插入对数组及表达式进行检查的语句是指在每一个数组表达式和指针表达式前面,按由内到外的顺序逐层检查,插入相应代码,以便可根据所述指针句柄表与颜色表,准确地检查出程序中指针越界和数组越界错误操作。
全文摘要
一种识别程序设计中内存操作错误的方法,对源程序的插装是基于包含有指针句柄表和颜色表的插装库进行的,对语句中包含有动态内存、变量和字符串常量的内存块时,插入登记内存块的语句;对指针赋值语句,插入登记指针并建立与内存块间关系的语句;对数组和表达式语句,插入对数组及表达式进行检查的语句。利用该方法可有效地检测出内存操作有关的编程错误,提高测试效率和程序质量,降低测试方面的费用开销。
文档编号G06F11/00GK1188933SQ98104528
公开日1998年7月29日 申请日期1998年2月6日 优先权日1998年2月6日
发明者陈青, 刘运渠, 肖华熙, 龙晶 申请人:深圳市华为技术有限公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1