一种源代码中值计算错误的自动检测和定位方法

文档序号:6628426阅读:293来源:国知局
一种源代码中值计算错误的自动检测和定位方法
【专利摘要】本发明公开了一种源代码中值计算错误的自动检测和定位方法,属于计算机软件测试领域,该方法利用编译器对源代码进行语法分析,构造抽象语法树,通过遍历抽象语法树,基于表达式类型和用户指定检测的值计算错误类型,判断是否存在值计算错误的潜在风险;对可能产生值计算错误的表达式进行源代码变换,加入值计算错误检测和源代码定位的机制;编译执行变换后的源代码,执行后的源代码程序会自动判断值计算错误的发生,并准确报告错误对应的源代码位置。本方法可以在软件运行过程中自动检测和定位软件中的值计算错误,以实现更准确的错误定位功能,更好的平台普适性,更高的运行时性能和效率,从而克服现有的检测方法中存在的技术问题。
【专利说明】一种源代码中值计算错误的自动检测和定位方法

【技术领域】
[0001] 本发明涉及一种源代码中值计算错误的自动检测和定位方法,属于计算机软件测 试领域。

【背景技术】
[0002] 值计算错误是一种普遍存在的软件安全漏洞,尤其是在C和C++程序中。值计算 错误包括:(1)除数为〇;(2)值溢出,包括值上溢、值下溢和精度丢失;(3)变量使用前未 初始化等。这些错误可能导致软件异常或系统崩溃,与缓冲区漏洞等技术结合可以被黑客 用来执行恶意代码。例如,1996年阿丽亚娜5号火箭的发射失败就是由于一个浮点数转 换为整数的精度丢失错误;Flash Oday漏洞和IE Oday漏洞允许黑客获得最高权限;在 MITRE2011年发布的报告中,值溢出漏洞被列为"25种最危险的软件错误"之一。对于安全 关键系统或安全关键应用,如果值计算错误引起系统错误或被黑客利用,将会造成巨大损 失。所以,实现值计算错误的高效自动检测和源代码定位,能够极大提高软件开发的质量和 维护的效率。
[0003] 目前,值计算错误的检测方法主要分为两类:静态检测和动态检测。
[0004] 静态检测是指在不运行软件的前提下,分析软件的设计模型、源代码或者二进制 代码,寻找可能导致软件失效的错误。其优点在于,通过对软件进行建模,保证了检测软件 行为的完备性。其缺点在于:(1)形式化验证会带来状态空间爆炸问题,检测时对系统资源 的要求较高,甚至无法在合理时间内完成验证;(2)由于使用模型抽象,检测结果存在误报 和漏报的可能性。
[0005] 动态检测是指利用软件运行过程中的输出等信息判断错误的发生,例如软件测试 技术和虚拟机技术。软件测试的优点在于,实现了测试用例管理和执行的自动化。其缺点 在于:(1)没有实现对错误发生位置的自动源代码定位;(2)开发人员需要重新手动调试运 行测试用例,效率较低。虚拟机技术通过对源代码的解释执行,在执行过程中对值计算错误 进行监控。其缺点在于:(1)依赖于特定的虚拟机环境,不具有普遍适用性;(2)虚拟机的解 释执行导致软件的性能和效率大幅度降低,不能被安全关键应用所接受。
[0006] 因此,有必要提供一种新的值计算错误的自动检测和源代码定位方法,以实现更 准确的错误定位功能,更好的平台普适性,更高的运行时性能和效率,从而克服现有的检测 方法中存在的技术问题。


【发明内容】

[0007] 发明目的:为了克服上述已有技术存在的不足,本发明的目的旨在提供一种源代 码中值计算错误的自动检测和定位方法,该方法通过使用源代码变换技术,将源代码变换 为带有自动检测和错误定位功能的源代码,使得可以在软件运行过程中自动检测和定位软 件中的值计算错误,以实现更准确的错误定位功能,更好的平台普适性,更高的运行时性能 和效率,从而克服现有的检测方法中存在的技术问题。
[0008] 为实现上述目的,本发明采用的技术方案为:一种源代码中值计算错误的自动检 测和定位方法,利用编译器对源代码进行语法分析,构造抽象语法树,通过遍历抽象语法 树,基于表达式类型和用户指定检测的值计算错误类型,判断是否存在值计算错误的潜在 风险;对可能产生值计算错误的表达式进行源代码变换,加入值计算错误检测和源代码定 位的机制;编译执行变换后的源代码,执行后的源代码程序会自动判断值计算错误的发生, 并准确报告错误对应的源代码位置。
[0009] 本发明的具体步骤如下:包括以下步骤:
[0010] 步骤S1,选择需要变换的源代码目录,或者单个源代码文件;
[0011] 步骤S2,指定需要检测的值计算错误类型:除数为0、值溢出、量使用前未初始化 中的一种或他们之间两种以上的组合;
[0012] 步骤S3,将选择的源代码目录或文件复制到源代码变换的工作目录中;
[0013] 步骤S4,对工作目录中的所有源文件进行宏扩展处理,并保存扩展结果到相应的 源文件中;
[0014] 步骤S5,遍历工作目录中的所有源文件,利用编译器生成符号表和抽象语法树;
[0015] 步骤S6,如果指定需要检测的值计算错误类型中包括除数为0错误,则进行除数 为〇错误分析和源代码变换计算;
[0016] 步骤S7,如果指定需要检测的值计算错误类型中包括值溢出错误,则进行值溢出 错误分析和源代码变换计算;
[0017] 步骤S8,如果指定需要检测的值计算错误类型中包括变量使用前未初始化错误, 则进行变量使用前未初始化错误分析和源代码变换计算;
[0018] 步骤S9,将步骤S6、S7或/和S8中所有替换修改写回到相应的源文件中,并根据 本次修改文件更新已处理文件列表;
[0019] 步骤S10,将经过变换的源代码目录或源代码文件按原有方式进行编译,生成可执 行文件;
[0020] 步骤S11,将可执行文件部署在目标平台上并运行,当出现值计算错误时,插入的 代码可以自动检测到错误的发生,并准确定位和报告值计算错误在源代码中的位置。
[0021] 经过上述步骤的操作,即可自动检测软件运行过程中的的值计算错误并定位。
[0022] 本发明提供的一种源代码中值计算错误的自动检测和定位方法,相比现有技术, 具有以下有益效果:
[0023] 1.与传统检测技术相比,本发明提供的值计算错误的自动检测和定位方法通过对 源代码的抽象语法树进行分析,具有充分的语义信息来判断潜在的值计算错误所在的源文 件和代码行,并相应地进行源代码变换,使得在错误检测中可以使用这些位置信息,因此具 有更准确的错误定位功能。
[0024] 2.本发明通过源代码变换技术,使得变换后的源代码可以使用原有编译器进行编 译和部署,因此具有更好的平台普适性。
[0025] 3.本发明通过对源代码的抽象语法树进行分析,具有充分的语义信息来判断潜在 的值计算错误的类型,并相应地进行源代码变换,减少了插入代码段的规模,简化了插入代 码段的复杂程度,从而获得了更高的运行时效率和性能。
[0026] 综上所述,本发明可以解决安全关键系统、安全关键应用及常用软件系统中值计 算错误检测和定位的难题,能够准确地自动检测和定位错误,实现更好的平台普适性,和更 高的运行时性能和效率,从而提高软件开发的质量和软件维护的效率,有良好的社会效益。

【专利附图】

【附图说明】
[0027] 图1为本发明的流程图。

【具体实施方式】
[0028] 下面结合具体实施例对本发明技术方案进行详细描述,但不作为本发明的限定。 本实施例采用本发明方法对一段C语言源代码进行检测和错误定位,进一步具体说明本发 明的有关方法、流程及相关步骤。
[0029] -种源代码中值计算错误的自动检测和定位方法,如图1所示,利用编译器对源 代码进行语法分析,构造抽象语法树,通过遍历抽象语法树,基于表达式类型和用户指定检 测的值计算错误类型,判断是否存在值计算错误的潜在风险;对可能产生值计算错误的表 达式进行源代码变换,加入值计算错误检测和源代码定位的机制;编译执行变换后的源代 码,执行后的源代码程序会自动判断值计算错误的发生,并准确报告错误对应的源代码位 置。
[0030] 本实施例采用本发明方法对一段C语言源代码进行检测和错误定位,本实例的源 代码如下(文件名为test, c):
[0031]
[0032]

【权利要求】
1. 一种源代码中值计算错误的自动检测和定位方法,其特征在于:利用编译器对源代 码进行语法分析,构造抽象语法树,通过遍历抽象语法树,基于表达式类型和用户指定检测 的值计算错误类型,判断是否存在值计算错误的潜在风险;对可能产生值计算错误的表达 式进行源代码变换,加入值计算错误检测和源代码定位的机制;编译执行变换后的源代码, 执行后的源代码程序会自动判断值计算错误的发生,并准确报告错误对应的源代码位置。
2. 根据权利要求1所述的源代码中值计算错误的自动检测和定位方法,其特征在于: 包括以下步骤: 步骤S1,选择需要变换的源代码目录,或者单个源代码文件; 步骤S2,指定需要检测的值计算错误类型:除数为0、值溢出、变量使用前未初始化中 的一种或他们之间两种以上的组合; 步骤S3,将选择的源代码目录或文件复制到源代码变换的工作目录中; 步骤S4,对工作目录中的所有源文件进行宏扩展处理,并保存扩展结果到相应的源文 件中; 步骤S5,遍历工作目录中的所有源文件,利用编译器生成符号表和抽象语法树; 步骤S6,如果指定需要检测的值计算错误类型中包括除数为0错误,则进行除数为0错 误分析和源代码变换计算; 步骤S7,如果指定需要检测的值计算错误类型中包括值溢出错误,则进行值溢出错误 分析和源代码变换计算; 步骤S8,如果指定需要检测的值计算错误类型中包括变量使用前未初始化错误,则进 行变量使用前未初始化错误分析和源代码变换计算; 步骤S9,将步骤S6、S7或/和S8中所有替换修改写回到相应的源文件中,并根据本次 修改文件更新已处理文件列表; 步骤S10,将经过变换的源代码目录或源代码文件按原有方式进行编译,生成可执行文 件; 步骤S11,将可执行文件部署在目标平台上并运行,当出现值计算错误时,插入的代码 可以自动检测到错误的发生,并准确定位和报告值计算错误在源代码中的位置。
3. 根据权利要求2所述的源代码中值计算错误的自动检测和定位方法,其特征在于: 所述步骤S4中的宏扩展处理包括: S41,利用编译器的词法分析器对文件进行词法分析,词法分析器返回经过宏扩展处理 之后的词法单元; S42,针对扩展自宏的词法单元,其属性中包括宏扩展之后的内容和宏扩展的位置,用 扩展之后的内容替换宏扩展位置的原有内容。
4. 根据权利要求3所述的源代码中值计算错误的自动检测和定位方法,其特征在于: 所述步骤S6中除数为0错误分析和源代码变换计算的方法如下:利用函数调用,在返回除 数给除法表达式之前,对除数进行检查,如果除数为0,则报告错误发生的源代码位置并结 束程序,如果除数不为0,则正常地将除数返回给除法表达式。
5. 根据权利要求4所述的源代码中值计算错误的自动检测和定位方法,其特征在于: 所述步骤S7中值溢出错误分析和源代码变换计算的方法如下:将可能产生值溢出错误的 表达式的操作数进行类型提升,然后将类型提升后的表达式值和原表达式值进行比较,如 果相同则说明未发生溢出,将原表达式值返回,如果不相同则说明发生溢出,报告错误发生 的源代码位置并结束程序。
6. 根据权利要求5所述的源代码中值计算错误的自动检测和定位方法,其特征在于: 所述步骤S8中变量使用前未初始化错误分析和源代码变换计算的方法如下:记录每一个 非全局且声明时未赋初值的变量的赋值状态,检查对于变量的引用,如果是对变量的赋值, 则更新该变量的赋值状态记录,如果是对变量值的使用,则检查该变量的赋值状态记录,未 赋值则表示出现变量使用前未初始化的错误,已赋值则表示没有出现该错误。
7. 根据权利要求6所述的源代码中值计算错误的自动检测和定位方法,其特征在于: 所述步骤S6中除数为0错误分析和源代码变换计算的方法包括以下步骤: 步骤S61,遍历编译器生成的抽象语法树,如果当前节点s所在文件路径不在工作目录 下,或已经存在于已处理文件列表中,则忽略该节点,不进行处理; 步骤S6101,如果当前节点s为除法表达式a6101/b6101,则从符号表中获取表达式 b6101的类型typeB6101,然后将表达式"a6101/b6101"替换为如下函数调用: a6101/(typeB6101) check_zero (b6101, fileNameS, lineS, columns) 其中check_zero为除0检测函数名,fileNameS, lineS, columns分别为节点s所在文 件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检 测函数声明插入位置集合declLocSet,表示此文件需要除0检测相关函数的声明; 步骤S6102,如果当前节点s为复合除赋值表达式a6102/ = b6102,则从符号表中获取 表达式b6102的类型typeB6102,然后将表达式"a6102/ = b6102"替换为如下函数调用: a6102/ = (typeB6102) check_zero (b6102, fileNameS, lineS, columns) 其中check_zero为除0检测函数名,fileNameS, lineS, columns分别为节点s所在文 件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检 测函数声明插入位置集合declLocSet,表示此文件需要除0检测相关函数的声明; 步骤S62,对于包含主函数声明的文件,在文件开始位置插入检测函数long double check-zero(long double num, const char氺fileName, unsigned line, unsigned column)的 定义,其中参数num代表除数,参数fileName,line, column分别代表运算发生位置所在文件 名,行号和列号;检测函数cheCk_zer〇判断表示除数的参数num是否为0,如果为0,则报告 除〇错误发生位置的文件名,行号和列号,并结束程序运行,否则将除数作为函数的返回值 返回; 步骤S63,根据检测函数声明插入位置集合declLocSet,在相应位置插入检测 函数 long double check_zero(long double num, const char*fileName, unsigned line, unsigned column)的声明;其中,参数 num 代表除数,参数 fileName,line,column 分别代表运算发生位置所在文件名,行号和列号;然后,将检测函数声明插入位置集合 declLocSet重置为空。
8. 根据权利要求7所述的源代码中值计算错误的自动检测和定位方法,其特征在于: 所述步骤S7中值溢出错误分析和源代码变换计算的方法包括以下步骤: 步骤S71,遍历编译器生成的抽象语法树,如果当前节点s所在文件路径不在工作目录 下,或已经存在于已处理文件列表中,则忽略该节点,不进行处理; 步骤S7101,如果当前节点s为后自增表达式a7101++,则从符号表中获取表达式a7101 的类型typeA7101 ;如果typeA7101为指针类型,则忽略节点s,不进行处理,否则将表达式 "a7101++"替换为如下逗号表达式: (pOverflowTemp = &(a7101), check_overflow(*(typeA7101*)pOverflowTemp+(typeA7101)1, * (typeA7101*) pOverf lowTemp+ (long double) 1, fileNameS, lineS, columns), ((* (typeA7101*)pOverflowTemp))++) 其中pOverflowTemp为空类型指针,用来存储表达式a7101的地址,check_overflow为 值溢出检测函数名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然 后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置 集合declLocSet,表示此文件需要值溢出检测相关函数的声明; 步骤S7102,如果当前节点s为后自减表达式a7102-,则从符号表中获取表达式a7102 的类型typeA7102 ;如果typeA7102为指针类型,则忽略节点s,不进行处理,否则将表达式 "a7102-_"替换为如下逗号表达式: (pOverflowTemp = &(a7102), check_overflow(*(typeA7102*)pOverflowTemp-(typeA7102)1, * (typeA7102*) pOverflowTemp- (long double) 1,fileNameS, lineS, columns), ((*(typeA7102*)pOverflowTemp))-) 其中pOverflowTemp为空类型指针,用来存储表达式a7102的地址,check_overflow为 值溢出检测函数名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然 后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置 集合declLocSet,表示此文件需要值溢出检测相关函数的声明; 步骤S7103,如果当前节点s为前自增表达式++a7103,则从符号表中获取表达式a7103 的类型typeA7103 ;如果typeA7103为指针类型,则忽略节点s,不进行处理,否则将表达式 "++a7103"替换为如下逗号表达式: (pOverflowTemp = &(a7103), check_overflow(*(typeA7103*)pOverflowTemp+(typeA7103)1, * (typeA7103*) pOverf lowTemp+ (long double) 1, fileNameS, lineS, columns), (++(*(typeA7103*)pOverflowTemp))) 其中pOverflowTemp为空类型指针,用来存储表达式a7103的地址,check_overflow为 值溢出检测函数名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然 后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置 集合declLocSet,表示此文件需要值溢出检测相关函数的声明; 步骤S7104,如果当前节点s为前自减表达式一a7104,则从符号表中获取表达式a7104 的类型typeA7104 ;如果typeA7104为指针类型,则忽略节点s,不进行处理,否则将表达式 "--a7104"替换为如下逗号表达式: (pOverflowTemp = &(a7104), check_overflow(*(typeA7104*)pOverflowTemp-(typeA7104)1, * (typeA7104*) pOverflowTemp- (long double) 1, fileNameS, lineS, columns), (-(* (typeA7104*)pOverflowTemp))) 其中pOverf lowTemp为空类型指针,用来存储表达式a7104的地址,check_overf low为 值溢出检测函数名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然 后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置 集合declLocSet,表示此文件需要值溢出检测相关函数的声明; 步骤S7105,如果当前节点s为取负表达式-a7105,则从符号表中获取表达式a7105的 类型typeA7105,将表达式"_a7105"替换为如下逗号表达式: (overflowTempl = (a7105), check-overflow (-(typeA7105)overflowTempl, -overflowTempl, fileNameS, lineS, columns), -(typeA7105) overf lowTempl) 其中overflowTempl为long double类型变量,用来记录表达式a7105的值,check_ overflow为值溢出检测函数名,fileNameS,lineS,columns分别为节点s所在文件名,行号 和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明 插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明; 步骤S7106,如果当前节点s为乘法表达式a7106*b7106,则从符号表中获取表达式 a7106的类型typeA7106,b7106的类型typeB7106,将表达式"a7106补7106"替换为如下逗 号表达式: (overflowTempl = (a7106), overflowStackPush(overflowTempl), overflowTemp2 = (b7106), overflowTempl = overflowStackPop(), check-overflow ((typeA7106)overflowTempl*(typeB7106)overflowTemp2, overflowTempl^overflowTemp2, fileNameS, lineS, columns), (typeA7106)overflowTempl^(typeB7106)overflowTemp2) 其中overf lowTempl和overf lowTemp2为long double类型变量,分别用来记录表达 式a7106和表达式b7106的值,overf lowStackPush和overf lowStackPop分别为栈结构的 压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columns分别 为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置 locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函 数的声明; 步骤S7107,如果当前节点s为除法表达式a7107/b7107,则从符号表中获取表达式 a7107的类型typeA7107,b7107的类型typeB7107,将表达式"a7107/b7107"替换为如下逗 号表达式: (overflowTempl = (a7107), overflowStackPush(overflowTempl), overflowTemp2 = (b7107), overflowTempl = overflowStackPop(), check-overflow ((typeA7107)overflowTempl/(typeB7107)overflowTemp2, overflowTempl/overflowTemp2, fileNameS, lineS, columns), (typeA7107) overflowTempl/(typeB7107)overflowTemp2) 其中overflowTempl和overflowTemp2为long double类型变量,分别用来记录表达 式a7107和表达式b7107的值,overflowStackPush和overflowStackPop分别为栈结构的 压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columns分别 为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置 locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函 数的声明; 步骤S7108,如果当前节点s为加法表达式a7108+b7108,则从符号表中获取表达式 a7108 的类型 typeA7108,b7108 的类型 typeB7108 ;如果 typeA7108 或 typeB7108 为指针类 型,则忽略节点s,不进行处理,否则将表达式"a7108+b7108"替换为如下逗号表达式: (overflowTempl = (a7108), overflowStackPush(overflowTempl), overflowTemp2 = (b7108), overflowTempl = overflowStackPop(), check_overflow ((typeA7108)overflowTempl+(typeB7108)overflowTemp2, overflowTempl+overflowTemp2, fileNameS, lineS, columns), (typeA7108)overflowTempl+(typeB7108)overflowTemp2) 其中overf lowTempl和overf lowTemp2为long double类型变量,分别用来记录表达 式a7108和表达式b7108的值,overf lowStackPush和overf lowStackPop分别为栈结构的 压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columns分别 为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置 locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函 数的声明; 步骤S7109,如果当前节点s为减法表达式a7109-b7109,则从符号表中获取表达式 a7109 的类型 typeA7109,b7109 的类型 typeB7109 ;如果 typeA7109 或 typeB7109 为指针类 型,则忽略节点s,不进行处理,否则将表达式"a7109-b7109"替换为如下逗号表达式: (overflowTempl = (a7109), overflowStackPush(overflowTempl), overflowTemp2 = (b7109), overflowTempl = overflowStackPop(), check_overflow ((typeA7109)overflowTempl-(typeB7109)overflowTemp2, overflowTempl-overflowTemp2, fileNameS, lineS, columns), (typeA7109)overflowTempl-(typeB7109)overflowTemp2) 其中overf lowTempl和overf lowTemp2为long double类型变量,分别用来记录表达 式a7109和表达式b7109的值,overf lowStackPush和overf lowStackPop分别为栈结构的 压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columns分别 为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置 locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函 数的声明; 步骤S7110,如果当前节点s为位左移表达式a7110〈〈b7110,则从符号表中获取表达式 a7110的类型typeA7110, b7110的类型typeB7110,将表达式"a7110〈〈b7110"替换为如下 逗号表达式: (overflowTempl = (a7110), overflowStackPush(overflowTempl), overflowTemp2 = (b7110), overflowTempl = overflowStackPop(), check_overflow ((typeA7110)overflowTempl<<(typeB7110)overflowTemp2, (long long int)overflowTempl<<(long long int)overflowTemp2, fileNameS,lineS,columnS), (typeA7110)overflowTempl<<(typeB7110)overflowTemp2) 其中overf lowTempl和overf lowTemp2为long double类型变量,分别用来记录表达 式a7110和表达式b7110的值,overflowStackPush和overflowStackPop分别为栈结构的 压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columns分别 为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置 locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函 数的声明; 步骤S7111,如果当前节点s为位右移表达式a7111?b7111,则从符号表中获取表达式 a7111的类型typeA7111,b7111的类型typeB7111,将表达式"a7111?b7111"替换为如下 逗号表达式: (overflowTempl = (a7111), overflowStackPush(overflowTempl), overflowTemp2 = (b7111), overflowTempl = overflowStackPop (), check_overflow ((typeA7111)overflowTempl>>(typeB7111)overflowTemp2, (long long int)overflowTempl>>(long long int)overflowTemp2, fileNameS,lineS,columnS), (typeA7111) overflowTempl>>(typeB7111)overflowTemp2) 其中overf lowTempl和overf lowTemp2为long double类型变量,分别用来记录表达 式a7111和表达式b7111的值,overflowStackPush和overflowStackPop分别为栈结构的 压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columns分别 为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置 locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函 数的声明; 步骤S7112,如果当前节点s为复合乘赋值表达式a7112* = b7112,则从符号表中获取 表达式 a7112 的类型 typeA7112,b7112 的类型 typeB7112,将表达式 "a7112* = b7112" 替 换为如下逗号表达式: (pOverflowTemp = &(a7112), overflowStackPush((long)pOverflowTemp), overflowTempl = (b7112), pOverflowTemp = (void*) (long)overflowStackPop(), check-overflow ((typeA7112)((*(typeA7112*)pOverflowTemp)* (typeB7112)overflowTempl),(*(typeA7112*)pOverflowTemp)*overflowTempl, fileNameS,lineS,columnS), (*(typeA7112*)p0verflowTemp)* = (typeB7112)overflowTempl) 其中pOverf lowTemp为空类型指针,用来存储表达式a7112的地址,overf lowTempl 为long double类型变量,用来记录表达式b7112的值,overflowStackPush和 overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数 名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然后,从抽象语法树 中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet, 表示此文件需要值溢出检测相关函数的声明; 步骤S7113,如果当前节点s为复合除赋值表达式a7113/= b7113,则从符号表中获取 表达式 a7113 的类型 typeA7113, b7113 的类型 typeB7113,将表达式 "a7113/ = b7113" 替 换为如下逗号表达式: (pOverflowTemp = &(a7113), overflowStackPush((long)pOverflowTemp), overflowTempl = (b7113), pOverflowTemp = (void^) (long)overflowStackPop (), check-overflow ((typeA7113)((*(typeA7113*)pOverflowTemp)/ (typeB7113) overflowTempl), (typeATllS^)pOverflowTemp)/overflowTempl, fileNameS,lineS,columnS), (*(typeA7113*)p0verflowTemp)/ = (typeB7113)overflowTempl) 其中pOverf lowTemp为空类型指针,用来存储表达式a7113的地址,overf lowTempl 为long double类型变量,用来记录表达式b7113的值,overflowStackPush和 overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数 名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然后,从抽象语法树 中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet, 表示此文件需要值溢出检测相关函数的声明; 步骤S7114,如果当前节点s为复合加赋值表达式a7114+= b7114,则从符号表中获取 表达式 a7114 的类型 typeA7114,b7114 的类型 typeB7114 ;如果 typeA7114 或 typeB7114 为指针类型,则忽略节点s,不进行处理,否则将表达式"a7114+ = b7114"替换为如下逗号 表达式: (pOverflowTemp = &(a7114), overflowStackPush((long)pOverflowTemp), overflowTempl = (b7114), pOverflowTemp = (void^) (long)overflowStackPop (), check-overflow ((typeA7114)((*(typeA7114*)pOverflowTemp) + (typeB7114)overflowTempl), (木(typeA7114*) pOverflowTemp) +overflowTempl,fileNameS,lineS,columns), (*(typeA7114*)p0verflowTemp)+ = (typeB7114)overflowTempl) 其中pOverflowTemp为空类型指针,用来存储表达式a7114的地址,overflowTempl 为long double类型变量,用来记录表达式b7114的值,overflowStackPush和 overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数 名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然后,从抽象语法树 中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet, 表示此文件需要值溢出检测相关函数的声明; 步骤S7115,如果当前节点s为复合减赋值表达式a7115-= b7115,则从符号表中获取 表达式 a7115 的类型 typeA7115, b7115 的类型 typeB7115 ;如果 typeA7115 或 typeB7115 为指针类型,则忽略节点s,不进行处理,否则将表达式"a7115- = b7115"替换为如下逗号 表达式: (pOverflowTemp = &(a7115), overflowStackPush((long)pOverflowTemp), overflowTempl = (b7115), pOverflowTemp = (void^) (long)overflowStackPop (), check_overflow ((typeA7115)((^(typeA7115^)pOverflowTemp)-(typeB7115)overflowTempl), (* (typeA7115*) pOverflowTemp) -overflowTempl,fileNameS,lineS,columns), (^(typeATl15^)pOverflowTemp) - = (typeB7115) overflowTempl) 其中pOverflowTemp为空类型指针,用来存储表达式a7115的地址,overflowTempl 为long double类型变量,用来记录表达式b7115的值,overflowStackPush和 overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数 名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然后,从抽象语法树 中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet, 表示此文件需要值溢出检测相关函数的声明; 步骤S7116,如果当前节点s为复合位左移赋值表达式a7116〈〈 = b7116,则从符号表 中获取表达式a7116的类型typeA7116, b7116的类型typeB7116,将表达式"a7116〈〈= b7116"替换为如下逗号表达式: (pOverflowTemp = &(a7116), overflowStackPush((long)pOverflowTemp), overflowTempl = (b7116), pOverflowTemp = (void^) (long)overflowStackPop (), check-overflow ((typeA7116)((*(typeA7116*)pOverflowTemp)〈〈 (typeB7116)overflowTempl), (long long int) (^(typeA7116^)pOverflowTemp) 〈〈(long long int)overflowTempl, fileNameS, lineS, columns), (5^ (typeA7116^) pOverflowTemp) << = (typeB7116) overflowTempl) 其中pOverflowTemp为空类型指针,用来存储表达式a7116的地址,overflowTempl 为long double类型变量,用来记录表达式b7116的值,overflowStackPush和 overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数 名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然后,从抽象语法树 中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet, 表示此文件需要值溢出检测相关函数的声明; 步骤S7117,如果当前节点s为复合位右移赋值表达式a7117>> = b7117,则从符号表 中获取表达式a7117的类型typeA7117, b7117的类型typeB7117,将表达式"a7117>> = b7117"替换为如下逗号表达式: (pOverflowTemp = &(a7117), overflowStackPush((long)pOverflowTemp), overflowTempl = (b7117), pOverflowTemp = (void^) (long)overflowStackPop (), check-overflow ((typeA7117)((*(typeA7117*)pOverflowTemp)>> (typeB7117)overflowTempl), (long long int) (typeA7117^)pOverflowTemp)>> (long long int) overf lowTempl, fileNameS, lineS, columns), (5^ (typeA7117^) pOverf lowTemp) >> = (typeB7117) overflowTempl) 其中pOverf lowTemp为空类型指针,用来存储表达式a7117的地址,overf lowTempl 为long double类型变量,用来记录表达式b7117的值,overflowStackPush和 overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数 名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然后,从抽象语法树 中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet, 表示此文件需要值溢出检测相关函数的声明; 步骤S7118,如果当前节点s为隐含转换表达式(typeCast7118)a7118,其中 typeCast7118为隐含转换类型,则从符号表中获取表达式a7118的类型typeA7118 ;如果 typeA7118和typeCast7118相同,忽略节点s,不进行处理,否则将表达式"(typeCast7118) a7118"替换为如下逗号表达式: (overflowTempl = (a7118), check_overflow ((typeCast7118)overflowTempl, overflowTempl,fileNameS,lineS,columnS), (typeCast7118)overflowTempl) 其中overflowTempl为long double类型变量,用来记录表达式a7118的值,check_ overflow为值溢出检测函数名,fileNameS,lineS,columns分别为节点s所在文件名,行号 和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明 插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明; 步骤S72,对于包含主函数声明的文件,在文件开始位置插入空类型指针 pOverflowTemp, long double 类型变量 overflowTempl 和 overflowTemp2,栈结构 struct OverflowStackNode,压栈函数 void overflowStackPush(long double num), 出栈函数 long double overf lowStackPop (),清空栈函数 void overf lowStackFree () 和值溢出检测函数 void check_overflow (long double numl,long double num2, const char 氺 fileName,unsigned line, unsigned column)的定义;其中,压找函数 overflowStackPush的参数num代表需要存储的表达式值,检测函数check_overflow的参 数numl和num2分别代表类型提升前表达式值和类型提升后表达式值,参数fileName,line, column分别代表运算发生位置所在文件名,行号和列号;检测函数check_overf low对参数 numl和num2进行比较:如果两个参数值相同,说明未发生值溢出,不执行任何动作;如果两 个参数值不相同,则说明发生了值溢出,报告值溢出错误发生位置的文件名,行号和列号, 清空栈并结束程序运行; 步骤S73,根据检测函数声明插入位置集合declLocSet,在相应位置插入空类型指 针 pOverflowTemp,long double 类型变量 overflowTempl 和 overflowTemp2,栈结构 struct OverflowStackNode,压栈函数 void overflowStackPush(long double num), 出栈函数 long double overflowStackPopO,清空栈函数 void overflowStackFreeO 和值溢出检测函数 void check_overflow(long double numl, long double num2, const char*fileName, unsigned line, unsigned column)的声明;其中,压栈函数 overflowStackPush的参数num代表需要存储的表达式值,检测函数check_overflow的参 数numl和num2分别代表类型提升前表达式值和类型提升后表达式值,参数fileName,line, column分别代表运算发生位置所在文件名,行号和列号;然后,将检测函数声明插入位置 集合declLocSet重置为空。
9.根据权利要求8所述的源代码中值计算错误的自动检测和定位方法,其特征在于: 所述步骤S8中变量使用前未初始化错误分析和源代码变换计算的方法包括以下步骤: 步骤S81,遍历编译器生成的抽象语法树,如果当前节点s所在文件路径不在工作目录 下,或已经存在于已处理文件列表中,则忽略该节点,不进行处理; 步骤S8101,如果当前节点s为声明语句,则遍历声明语句中的每一个声明a8101,并 通过抽象语法树获得声明a8101的属性;如果声明a8101同时满足如下条件:(1)为变量声 明;(2)非全局变量声明;(3)非函数参数声明;(4)声明没有给出初始化表达式,贝1J将变量 声明a8101绑定一个编号varlndex ;编号从1开始依次选取,所以varlndex也作为记录变 量声明总数的计数器; 步骤S8102,如果当前节点s为变量声明引用a8102,考察节点s在抽象语法树中的父 节点;如果s的父节点为隐含左值向右值转换表达式,自增表达式或自减表达式,忽略节点 s,不进行处理,否则,表明节点s为对变量的赋值,利用步骤S8101得到的变量声明和编号 的绑定关系,查询得a8102所引用变量声明对应编号indexTemp8102,将表达式"a8102"替 换为如下逗号表达式: * (fileName_set_uninit (indexTemp8102),&(a8102)) 其中fileName为节点s所在文件名,并作为fileName_set_uninit的一部分构成变量赋 值状态设置函数名;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检 测函数定义代码插入位置集合defLocSet,表示此文件需要变量使用前未初始化检测相关 函数的定义; 步骤S8103,如果当前节点s为隐含转换表达式(typeCast8103)a8103,考察该节点:如 果typeCaSt8103不是左值向右值的转换或a8103不是变量声明引用,忽略节点s,不进行处 理,否则,表明节点s为对变量值的引用,利用步骤S8101得到的变量声明和编号的绑定关 系,查询得a8103所引用变量声明对应编号indexTemp8103,将表达式"a8103"替换为如下 逗号表达式: (fileName_check_uninit (indexTemp8103, fileNameS, lineS, columns), a8103) 其中fileName为节点s所在文件名,并作为fileName_check_uninit的一部分构成赋值 状态检测函数名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然后, 从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数定义代码插入位置 集合defLocSet,表示此文件需要变量使用前未初始化检测相关函数的定义; 步骤S8104,如果当前节点s为自增或自减表达式++a8104, 一a8104, a8104++或 a8104-,考察该节点:如果a8104不是变量声明引用,忽略节点s,不进行处理,否则,表 明节点s为对变量值的引用,利用步骤S8101得到的变量声明和编号的绑定关系,查询得 a8104所引用变量声明对应编号indexTemp8104,将表达式"a8104"替换为如下逗号表达 式: * (fileName_check_uninit (indexTemp8104, fileNameS, lineS, columns), &a8104)其中 fileName为节点s所在文件名,并作为fileName_check_uninit的一部分构成赋值状态检 测函数名,fileNameS,lineS,columns分别为节点s所在文件名,行号和列号;然后,从抽象 语法树中获得节点s所在文件的开始位置locS,加入到检测函数定义代码插入位置集合 defLocSet,表示此文件需要变量使用前未初始化检测相关函数的定义; 步骤S82,根据检测函数定义代码插入位置集合defLocSet,在相应位置插入变量赋值 状态数组fileName_varArray,赋值状态设置函数 void fileName_set_uninit (long index), 赋值状态检测函数 void fileName_check_uninit (long index, char*fileName, unsigned line, unsigned column)的定义;其中,fileName为插入位置所在文件名,构成数组名和函 数名的一部分;数组fileName_varArray的类型为_Bool,数组大小由步骤S8101的变量声 明总数的计数器决定,数组元素初始值均为〇 ;函数fileName_set_uninit的参数index代 表变量声明对应的编号,函数fileName_check_uninit的参数index代表变量声明对应的编 号,参数fileName, line, column分别代表变量声明引用位置所在文件名,行号和列号;函数 fileName_set_uninit 将数组兀素 fileName_varArray[index]的值设置为 1,函数 fileName_ check_uninit对数组元素 fileName_varArray[index]的值进行检查:如果为1,说明未发生 错误,不执行任何动作;如果为〇,则说明发生了变量使用前未初始化错误,报告错误发生 位置的文件名,行号和列号,并结束程序运行。
【文档编号】G06F21/57GK104298594SQ201410499170
【公开日】2015年1月21日 申请日期:2014年9月25日 优先权日:2014年9月25日
【发明者】陈哲, 朱云龙, 魏欧, 黄志球 申请人:南京航空航天大学
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1