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

上传人:1****2 文档编号:4562912 上传时间:2018-10-20 格式:PDF 页数:37 大小:2.08MB
返回 下载 相关 举报
摘要
申请专利号:

CN201410499170.9

申请日:

2014.09.25

公开号:

CN104298594A

公开日:

2015.01.21

当前法律状态:

授权

有效性:

有权

法律详情:

授权|||实质审查的生效IPC(主分类):G06F 11/36申请日:20140925|||公开

IPC分类号:

G06F11/36; G06F21/57(2013.01)I

主分类号:

G06F11/36

申请人:

南京航空航天大学

发明人:

陈哲; 朱云龙; 魏欧; 黄志球

地址:

210016 江苏省南京市秦淮区御道街29号

优先权:

专利代理机构:

南京瑞弘专利商标事务所(普通合伙) 32249

代理人:

杨晓玲

PDF下载: PDF下载
内容摘要

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

权利要求书

权利要求书
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_zero判断表示除数的参数num是否为0,如果为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*)pOverflowTemp+(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*)pOverflowTemp+(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)))
其中pOverflowTemp为空类型指针,用来存储表达式a7104的地址,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明;
步骤S7105,如果当前节点s为取负表达式-a7105,则从符号表中获取表达式a7105的类型typeA7105,将表达式“-a7105”替换为如下逗号表达式:
(overflowTemp1=(a7105),
check_overflow(-(typeA7105)overflowTemp1,
-overflowTemp1,fileNameS,lineS,columnS),
-(typeA7105)overflowTemp1)
其中overflowTemp1为long double类型变量,用来记录表达式a7105的值,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明;
步骤S7106,如果当前节点s为乘法表达式a7106*b7106,则从符号表中获取表达式a7106的类型typeA7106,b7106的类型typeB7106,将表达式“a7106*b7106”替换为如下逗号表达式:
(overflowTemp1=(a7106),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7106),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7106)overflowTemp1*(typeB7106)overflowTemp2,
             overflowTemp1*overflowTemp2,fileNameS,lineS,columnS),
(typeA7106)overflowTemp1*(typeB7106)overflowTemp2)
其中overflowTemp1和overflowTemp2为long double类型变量,分别用来记录表达式a7106和表达式b7106的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明;
步骤S7107,如果当前节点s为除法表达式a7107/b7107,则从符号表中获取表达式a7107的类型typeA7107,b7107的类型typeB7107,将表达式“a7107/b7107”替换为如下逗号表达式:
(overflowTemp1=(a7107),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7107),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7107)overflowTemp1/(typeB7107)overflowTemp2,
             overflowTemp1/overflowTemp2,fileNameS,lineS,columnS),
(typeA7107)overflowTemp1/(typeB7107)overflowTemp2)
其中overflowTemp1和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”替换为如下逗号表达式:
(overflowTemp1=(a7108),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7108),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7108)overflowTemp1+(typeB7108)overflowTemp2,
             overflowTemp1+overflowTemp2,fileNameS,lineS,columnS),
(typeA7108)overflowTemp1+(typeB7108)overflowTemp2)
其中overflowTemp1和overflowTemp2为long double类型变量,分别用来记录表达式a7108和表达式b7108的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明;
步骤S7109,如果当前节点s为减法表达式a7109-b7109,则从符号表中获取表达式a7109的类型typeA7109,b7109的类型typeB7109;如果typeA7109或typeB7109为指针类型,则忽略节点s,不进行处理,否则将表达式“a7109-b7109”替换为如下逗号表达式:
(overflowTemp1=(a7109),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7109),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7109)overflowTemp1-(typeB7109)overflowTemp2,
             overflowTemp1-overflowTemp2,fileNameS,lineS,columnS),
(typeA7109)overflowTemp1-(typeB7109)overflowTemp2)
其中overflowTemp1和overflowTemp2为long double类型变量,分别用来记录表达式a7109和表达式b7109的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明;
步骤S7110,如果当前节点s为位左移表达式a7110<<b7110,则从符号表中获取表达式a7110的类型typeA7110,b7110的类型typeB7110,将表达式“a7110<<b7110”替 换为如下逗号表达式:
(overflowTemp1=(a7110),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7110),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7110)overflowTemp1<<(typeB7110)overflowTemp2,
       (long long int)overflowTemp1<<(long long int)overflowTemp2,
       fileNameS,lineS,columnS),
(typeA7110)overflowTemp1<<(typeB7110)overflowTemp2)
其中overflowTemp1和overflowTemp2为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”替换为如下逗号表达式:
(overflowTemp1=(a7111),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7111),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7111)overflowTemp1>>(typeB7111)overflowTemp2,
      (long long int)overflowTemp1>>(long long int)overflowTemp2,
       fileNameS,lineS,columnS),
(typeA7111)overflowTemp1>>(typeB7111)overflowTemp2)
其中overflowTemp1和overflowTemp2为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),
overflowTemp1=(b7112),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7112)((*(typeA7112*)pOverflowTemp)*
(typeB7112)overflowTemp1),(*(typeA7112*)pOverflowTemp)*overflowTemp1,
fileNameS,lineS,columnS),
(*(typeA7112*)pOverflowTemp)*=(typeB7112)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7112的地址,overflowTemp1为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),
overflowTemp1=(b7113),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7113)((*(typeA7113*)pOverflowTemp)/(typeB7113)
overflowTemp1),(*(typeA7113*)pOverflowTemp)/overflowTemp1,
fileNameS,lineS,columnS),
(*(typeA7113*)pOverflowTemp)/=(typeB7113)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7113的地址,overflowTemp1为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),
overflowTemp1=(b7114),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7114)((*(typeA7114*)pOverflowTemp)+
(typeB7114)overflowTemp1),
(*(typeA7114*)pOverflowTemp)+overflowTemp1,fileNameS,lineS,columnS),
(*(typeA7114*)pOverflowTemp)+=(typeB7114)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7114的地址,overflowTemp1为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),
overflowTemp1=(b7115),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7115)((*(typeA7115*)pOverflowTemp)-
(typeB7115)overflowTemp1),
(*(typeA7115*)pOverflowTemp)-overflowTemp1,fileNameS,lineS,columnS),
(*(typeA7115*)pOverflowTemp)-=(typeB7115)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7115的地址,overflowTemp1为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),
overflowTemp1=(b7116),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7116)((*(typeA7116*)pOverflowTemp)<<
(typeB7116)overflowTemp1),(long long int)(*(typeA7116*)pOverflowTemp)
<<(long long int)overflowTemp1,fileNameS,lineS,columnS),
(*(typeA7116*)pOverflowTemp)<<=(typeB7116)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7116的地址,overflowTemp1为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),
overflowTemp1=(b7117),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7117)((*(typeA7117*)pOverflowTemp)>>
(typeB7117)overflowTemp1),(long long int)(*(typeA7117*)pOverflowTemp)>>
(long long int)overflowTemp1,fileNameS,lineS,columnS),
(*(typeA7117*)pOverflowTemp)>>=(typeB7117)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7117的地址,overflowTemp1为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”替换为如下逗号表达式:
(overflowTemp1=(a7118),
check_overflow((typeCast7118)overflowTemp1,
overflowTemp1,fileNameS,lineS,columnS),
(typeCast7118)overflowTemp1)
其中overflowTemp1为long double类型变量,用来记录表达式a7118的值, check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明;
步骤S72,对于包含主函数声明的文件,在文件开始位置插入空类型指针pOverflowTemp,long double类型变量overflowTemp1和overflowTemp2,栈结构struct OverflowStackNode,压栈函数void overflowStackPush(long double num),出栈函数long double overflowStackPop(),清空栈函数void overflowStackFree()和值溢出检测函数void check_overflow(long double num1,long double num2,const char*fileName,unsigned line,unsigned column)的定义;其中,压栈函数overflowStackPush的参数num代表需要存储的表达式值,检测函数check_overflow的参数num1和num2分别代表类型提升前表达式值和类型提升后表达式值,参数fileName,line,column分别代表运算发生位置所在文件名,行号和列号;检测函数check_overflow对参数num1和num2进行比较:如果两个参数值相同,说明未发生值溢出,不执行任何动作;如果两个参数值不相同,则说明发生了值溢出,报告值溢出错误发生位置的文件名,行号和列号,清空栈并结束程序运行;
步骤S73,根据检测函数声明插入位置集合declLocSet,在相应位置插入空类型指针pOverflowTemp,long double类型变量overflowTemp1和overflowTemp2,栈结构struct OverflowStackNode,压栈函数void overflowStackPush(long double num),出栈函数long double overflowStackPop(),清空栈函数void overflowStackFree()和值溢出检测函数void check_overflow(long double num1,long double num2,const char*fileName,unsigned line,unsigned column)的声明;其中,压栈函数overflowStackPush的参数num代表需要存储的表达式值,检测函数check_overflow的参数num1和num2分别代表类型提升前表达式值和类型提升后表达式值,参数fileName,line,column分别代表运算发生位置所在文件名,行号和列号;然后,将检测函数声明插入位置集合declLocSet重置为空。

9.  根据权利要求8所述的源代码中值计算错误的自动检测和定位方法,其特征在于:所述步骤S8中变量使用前未初始化错误分析和源代码变换计算的方法包括以下步骤:
步骤S81,遍历编译器生成的抽象语法树,如果当前节点s所在文件路径不在工作目录下,或已经存在于已处理文件列表中,则忽略该节点,不进行处理;
步骤S8101,如果当前节点s为声明语句,则遍历声明语句中的每一个声明a8101,并通过抽象语法树获得声明a8101的属性;如果声明a8101同时满足如下条件:(1)为变量声明;(2)非全局变量声明;(3)非函数参数声明;(4)声明没有给出初始化表达式,则将变量声明a8101绑定一个编号varIndex;编号从1开始依次选取,所以varIndex也作为记录变量声明总数的计数器;
步骤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的变量声明总数的计数器决定,数组元素初始值均为0;函数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,说明未发生错误,不执行任何动作;如果为0,则说明发生了变量使用前未初始化错误,报告错误发生位置的文件名,行号和列号,并结束程序运行。

说明书

说明书一种源代码中值计算错误的自动检测和定位方法
技术领域
本发明涉及一种源代码中值计算错误的自动检测和定位方法,属于计算机软件测试领域。
背景技术
值计算错误是一种普遍存在的软件安全漏洞,尤其是在C和C++程序中。值计算错误包括:(1)除数为0;(2)值溢出,包括值上溢、值下溢和精度丢失;(3)变量使用前未初始化等。这些错误可能导致软件异常或系统崩溃,与缓冲区漏洞等技术结合可以被黑客用来执行恶意代码。例如,1996年阿丽亚娜5号火箭的发射失败就是由于一个浮点数转换为整数的精度丢失错误;Flash 0day漏洞和IE 0day漏洞允许黑客获得最高权限;在MITRE2011年发布的报告中,值溢出漏洞被列为“25种最危险的软件错误”之一。对于安全关键系统或安全关键应用,如果值计算错误引起系统错误或被黑客利用,将会造成巨大损失。所以,实现值计算错误的高效自动检测和源代码定位,能够极大提高软件开发的质量和维护的效率。
目前,值计算错误的检测方法主要分为两类:静态检测和动态检测。
静态检测是指在不运行软件的前提下,分析软件的设计模型、源代码或者二进制代码,寻找可能导致软件失效的错误。其优点在于,通过对软件进行建模,保证了检测软件行为的完备性。其缺点在于:(1)形式化验证会带来状态空间爆炸问题,检测时对系统资源的要求较高,甚至无法在合理时间内完成验证;(2)由于使用模型抽象,检测结果存在误报和漏报的可能性。
动态检测是指利用软件运行过程中的输出等信息判断错误的发生,例如软件测试技术和虚拟机技术。软件测试的优点在于,实现了测试用例管理和执行的自动化。其缺点在于:(1)没有实现对错误发生位置的自动源代码定位;(2)开发人员需要重新手动调试运行测试用例,效率较低。虚拟机技术通过对源代码的解释执行,在执行过程中对值计算错误进行监控。其缺点在于:(1)依赖于特定的虚拟机环境,不具有普遍适用性;(2)虚拟机的解释执行导致软件的性能和效率大幅度降低,不能被安全关键应用所接受。
因此,有必要提供一种新的值计算错误的自动检测和源代码定位方法,以实现更准 确的错误定位功能,更好的平台普适性,更高的运行时性能和效率,从而克服现有的检测方法中存在的技术问题。
发明内容
发明目的:为了克服上述已有技术存在的不足,本发明的目的旨在提供一种源代码中值计算错误的自动检测和定位方法,该方法通过使用源代码变换技术,将源代码变换为带有自动检测和错误定位功能的源代码,使得可以在软件运行过程中自动检测和定位软件中的值计算错误,以实现更准确的错误定位功能,更好的平台普适性,更高的运行时性能和效率,从而克服现有的检测方法中存在的技术问题。
为实现上述目的,本发明采用的技术方案为:一种源代码中值计算错误的自动检测和定位方法,利用编译器对源代码进行语法分析,构造抽象语法树,通过遍历抽象语法树,基于表达式类型和用户指定检测的值计算错误类型,判断是否存在值计算错误的潜在风险;对可能产生值计算错误的表达式进行源代码变换,加入值计算错误检测和源代码定位的机制;编译执行变换后的源代码,执行后的源代码程序会自动判断值计算错误的发生,并准确报告错误对应的源代码位置。
本发明的具体步骤如下:包括以下步骤:
步骤S1,选择需要变换的源代码目录,或者单个源代码文件;
步骤S2,指定需要检测的值计算错误类型:除数为0、值溢出、量使用前未初始化中的一种或他们之间两种以上的组合;
步骤S3,将选择的源代码目录或文件复制到源代码变换的工作目录中;
步骤S4,对工作目录中的所有源文件进行宏扩展处理,并保存扩展结果到相应的源文件中;
步骤S5,遍历工作目录中的所有源文件,利用编译器生成符号表和抽象语法树;
步骤S6,如果指定需要检测的值计算错误类型中包括除数为0错误,则进行除数为0错误分析和源代码变换计算;
步骤S7,如果指定需要检测的值计算错误类型中包括值溢出错误,则进行值溢出错误分析和源代码变换计算;
步骤S8,如果指定需要检测的值计算错误类型中包括变量使用前未初始化错误,则进行变量使用前未初始化错误分析和源代码变换计算;
步骤S9,将步骤S6、S7或/和S8中所有替换修改写回到相应的源文件中,并根据 本次修改文件更新已处理文件列表;
步骤S10,将经过变换的源代码目录或源代码文件按原有方式进行编译,生成可执行文件;
步骤S11,将可执行文件部署在目标平台上并运行,当出现值计算错误时,插入的代码可以自动检测到错误的发生,并准确定位和报告值计算错误在源代码中的位置。
经过上述步骤的操作,即可自动检测软件运行过程中的的值计算错误并定位。
本发明提供的一种源代码中值计算错误的自动检测和定位方法,相比现有技术,具有以下有益效果:
1.与传统检测技术相比,本发明提供的值计算错误的自动检测和定位方法通过对源代码的抽象语法树进行分析,具有充分的语义信息来判断潜在的值计算错误所在的源文件和代码行,并相应地进行源代码变换,使得在错误检测中可以使用这些位置信息,因此具有更准确的错误定位功能。
2.本发明通过源代码变换技术,使得变换后的源代码可以使用原有编译器进行编译和部署,因此具有更好的平台普适性。
3.本发明通过对源代码的抽象语法树进行分析,具有充分的语义信息来判断潜在的值计算错误的类型,并相应地进行源代码变换,减少了插入代码段的规模,简化了插入代码段的复杂程度,从而获得了更高的运行时效率和性能。
综上所述,本发明可以解决安全关键系统、安全关键应用及常用软件系统中值计算错误检测和定位的难题,能够准确地自动检测和定位错误,实现更好的平台普适性,和更高的运行时性能和效率,从而提高软件开发的质量和软件维护的效率,有良好的社会效益。
附图说明
图1为本发明的流程图。
具体实施方式
下面结合具体实施例对本发明技术方案进行详细描述,但不作为本发明的限定。本实施例采用本发明方法对一段C语言源代码进行检测和错误定位,进一步具体说明本发明的有关方法、流程及相关步骤。
一种源代码中值计算错误的自动检测和定位方法,如图1所示,利用编译器对源代码进行语法分析,构造抽象语法树,通过遍历抽象语法树,基于表达式类型和用户指定 检测的值计算错误类型,判断是否存在值计算错误的潜在风险;对可能产生值计算错误的表达式进行源代码变换,加入值计算错误检测和源代码定位的机制;编译执行变换后的源代码,执行后的源代码程序会自动判断值计算错误的发生,并准确报告错误对应的源代码位置。
本实施例采用本发明方法对一段C语言源代码进行检测和错误定位,本实例的源代码如下(文件名为test.c):


本发明方法的具体操作步骤如下:
步骤S1,选择需要变换的源代码目录,或者单个源代码文件。
本例中,选择源代码文件test.c。
步骤S2,指定需要检测的值计算错误类型:除数为0,值溢出,变量使用前未初始化中的一种或几种。
本例中,指定需要检测的值计算错误类型包括除数为0,值溢出和变量使用前未初始化共三种。
步骤S3,将选择的源代码目录或文件复制到源代码变换的工作目录中。
本例中,将源代码文件test.c复制到工作目录/tmp/work/中。
步骤S4,对工作目录中的所有源文件进行宏扩展处理,并保存扩展结果到相应的源文件中。进一步地,宏扩展处理具体包括:操作1、利用编译器的词法分析器对文件进行词法分析,词法分析器返回经过宏扩展处理之后的词法单元;操作2、针对扩展自宏的词法单元,其属性中包括宏扩展之后的内容和宏扩展的位置,用扩展之后的内容替换宏扩展位置的原有内容。
本例中,将第3行的语句“int temp1=N”替换为“int temp1=2”,并保存扩展结果到test.c文件中。
步骤S5,遍历工作目录中的所有源文件,利用编译器生成符号表和抽象语法树。
本例中,因为只有一个文件test.c,利用编译器生成test.c对应的符号表和抽象语法树。
步骤S6,如果指定需要检测的值计算错误类型中包括除数为0错误,则转至步骤S61;否则,略过中间步骤,直接转至步骤S7。
本例中,指定需要检测的值计算错误类型中包括除数为0错误,转至步骤S61。
步骤S61,遍历编译器生成的抽象语法树,如果当前节点s所在文件路径不在工作目录下,或已经存在于已处理文件列表中,则忽略该节点,不进行处理。
本例中,遍历test.c对应的抽象语法树,所有节点所在文件路径均在工作目录/tmp/work下,且初始时已处理文件列表set<string>类型容器变量parsedFileSet的元素为空,所以不存在忽略节点的情况。
步骤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检测相关函数的声明。
本例中,将第10行的表达式“temp1/temp2”替换为如下函数调用:
temp1/(int)check_zero(temp2,“test.c”,10,15)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要除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检测相关函数的声明。
本例中,将第16行的表达式“result/=temp2”替换为如下函数调用:
result/=(int)check_zero(temp2,“test.c”,16,9)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要除0检测相关函数的声明。
步骤S62,对于包含主函数声明的文件,在文件开始位置插入检测函数long double check_zero(long double num,const char*fileName,unsigned line,unsigned column)的定义,其中参数num代表除数,参数fileName,line,column分别代表运算发生位置所在文件名,行号和列号。检测函数check_zero判断表示除数的参数num是否为0,如果为0,则报告除0错误发生位置的文件名,行号和列号,并结束程序运行,否则将除数作为函数的返回值返回。
本例中,test.c文件中包含主函数声明,所以在test.c文件开始位置插入检测函 数的定义代码如下:

步骤S63,根据检测函数声明插入位置集合declLocSet,在相应位置插入检测函数long double check_zero(long double num,const char*fileName,unsigned line,unsigned column)的声明。其中,参数num代表除数,参数fileName,line,column分别代表运算发生位置所在文件名,行号和列号。然后,将检测函数声明插入位置集合declLocSet重置为空。
本例中,表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet只包含有表示test.c文件开始位置的SourceLocation类型变量loc。所以,在test.c文件开始位置插入检测函数声明代码如下:
01extern long double check_zero(long double num,const char*fileName,
02                                  unsigned line,unsigned column);
然后,将表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet重置为空。
步骤S7,如果指定需要检测的值计算错误类型中包括值溢出错误,则转至步骤S71;否则,略过中间步骤,直接转至步骤S8。
本例中,指定需要检测的值计算错误类型中包括值溢出错误,转至步骤S71。
步骤S71,遍历编译器生成的抽象语法树,如果当前节点s所在文件路径不在工作目录下,或已经存在于已处理文件列表中,则忽略该节点,不进行处理。
本例中,遍历test.c对应的抽象语法树,所有节点所在文件路径均在工作目录/tmp/work下,且初始时已处理文件列表set<string>类型容器变量parsedFileSet元素为空,所以不存在忽略节点的情况。
步骤S7101,如果当前节点s为后自增表达式a7101++,则从符号表中获取表达式a7101的类型typeA7101;如果typeA7101为指针类型,则忽略节点s,不进行处理,否则将表达式“a7101++”替换为如下逗号表达式:
(pOverflowTemp=&(a7101),
check_overflow(*(typeA7101*)pOverflowTemp+(typeA7101)1,
*(typeA7101*)pOverflowTemp+(long double)1,fileNameS,lineS,columnS),
((*(typeA7101*)pOverflowTemp))++)
其中pOverflowTemp为空类型指针,用来存储表达式a7101的地址,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号。然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第4行表达式“temp1++”替换为如下逗号表达式:
(pOverflowTemp=&(temp1),
check_overflow(*(int*)pOverflowTemp+(int)1,
*(int*)pOverflowTemp+(long double)1,“test.c”,4,15),
((*(int*)pOverflowTemp))++)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤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,表示此文件需要值溢出检测相关函数的声明。
本例中,将第5行表达式“temp1--”替换为如下逗号表达式:
(pOverflowTemp=&(temp1),
check_overflow(*(int*)pOverflowTemp-(int)1,
*(int*)pOverflowTemp-(long double)1,“test.c”,5,15),
((*(int*)pOverflowTemp))--)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7103,如果当前节点s为前自增表达式++a7103,则从符号表中获取表达式a7103的类型typeA7103;如果typeA7103为指针类型,则忽略节点s,不进行处理,否则将表达式“++a7103”替换为如下逗号表达式:
(pOverflowTemp=&(a7103),
check_overflow(*(typeA7103*)pOverflowTemp+(typeA7103)1,
*(typeA7103*)pOverflowTemp+(long double)1,fileNameS,lineS,columnS),
(++(*(typeA7103*)pOverflowTemp)))
其中pOverflowTemp为空类型指针,用来存储表达式a7103的地址,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第6行表达式“++temp1”替换为如下逗号表达式:
(pOverflowTemp=&(temp1),
check_overflow(*(int*)pOverflowTemp+(int)1,
*(int*)pOverflowTemp+(long double)1,“test.c”,6,10),
(++(*(int*)pOverflowTemp)))
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc, 加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤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)))
其中pOverflowTemp为空类型指针,用来存储表达式a7104的地址,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第7行表达式“--temp3”替换为如下逗号表达式:
(pOverflowTemp=&(temp3),
check_overflow(*(int*)pOverflowTemp-(int)1,
*(int*)pOverflowTemp-(long double)1,“test.c”,7,10),
(--(*(int*)pOverflowTemp)))
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7105,如果当前节点s为取负表达式-a7105,则从符号表中获取表达式a7105的类型typeA7105,将表达式“-a7105”替换为如下逗号表达式:
(overflowTemp1=(a7105),
check_overflow(-(typeA7105)overflowTemp1,
-overflowTemp1,fileNameS,lineS,columnS),
-(typeA7105)overflowTemp1)
其中overflowTemp1为long double类型变量,用来记录表达式a7105的值,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在 文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第8行表达式“-temp1”替换为如下逗号表达式:
(overflowTemp1=(temp1),
check_overflow(-(int)overflowTemp1,-overflowTemp1,“test.c”,8,10),
-(int)overflowTemp1)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7106,如果当前节点s为乘法表达式a7106*b7106,则从符号表中获取表达式a7106的类型typeA7106,b7106的类型typeB7106,将表达式“a7106*b7106”替换为如下逗号表达式:
(overflowTemp1=(a7106),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7106),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7106)overflowTemp1*(typeB7106)overflowTemp2,
             overflowTemp1*overflowTemp2,fileNameS,lineS,columnS),
(typeA7106)overflowTemp1*(typeB7106)overflowTemp2)
其中overflowTemp1和overflowTemp2为long double类型变量,分别用来记录表达式a7106和表达式b7106的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第9行表达式“temp1*temp2”替换为如下逗号表达式:
(overflowTemp1=(temp1),
overflowStackPush(overflowTemp1),
overflowTemp2=(temp2),
overflowTemp1=overflowStackPop(),
check_overflow((int)overflowTemp1*(int)overflowTemp2,
             overflowTemp1*overflowTemp2,“test.c”,9,15),
(int)overflowTemp1*(int)overflowTemp2)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7107,如果当前节点s为除法表达式a7107/b7107,则从符号表中获取表达式a7107的类型typeA7107,b7107的类型typeB7107,将表达式“a7107/b7107”替换为如下逗号表达式:
(overflowTemp1=(a7107),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7107),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7107)overflowTemp1/(typeB7107)overflowTemp2,
             overflowTemp1/overflowTemp2,fileNameS,lineS,columnS),
(typeA7107)overflowTemp1/(typeB7107)overflowTemp2)
其中overflowTemp1和overflowTemp2为long double类型变量,分别用来记录表达式a7107和表达式b7107的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第10行表达式“temp1/temp2”替换为逗号表达式,特别地,由于在步骤S6101中对表达式“temp1/temp2”已进行了一次替换,所以综合两次操作表达式“temp1/temp2”将被替换为:
(overflowTemp1=(temp1),
overflowStackPush(overflowTemp1),
overflowTemp2=((int)check_zero(temp2,“test.c”,10,15)),
overflowTemp1=overflowStackPop(),
check_overflow((int)overflowTemp1/(int)overflowTemp2,
             overflowTemp1/overflowTemp2,“test.c”,10,15),
(int)overflowTemp1/(int)overflowTemp2)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7108,如果当前节点s为加法表达式a7108+b7108,则从符号表中获取表达式a7108的类型typeA7108,b7108的类型typeB7108;如果typeA7108或typeB7108为指针类型,则忽略节点s,不进行处理,否则将表达式“a7108+b7108”替换为如下逗号表达式:
(overflowTemp1=(a7108),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7108),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7108)overflowTemp1+(typeB7108)overflowTemp2,
             overflowTemp1+overflowTemp2,fileNameS,lineS,columnS),
(typeA7108)overflowTemp1+(typeB7108)overflowTemp2)
其中overflowTemp1和overflowTemp2为long double类型变量,分别用来记录表达式a7108和表达式b7108的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第11行表达式“temp1+temp2”替换为如下逗号表达式:
(overflowTemp1=(temp1),
overflowStackPush(overflowTemp1),
overflowTemp2=(temp2),
overflowTemp1=overflowStackPop(),
check_overflow((int)overflowTemp1+(int)overflowTemp2,
             overflowTemp1+overflowTemp2,“test.c”,11,15),
(int)overflowTemp1+(int)overflowTemp2)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7109,如果当前节点s为减法表达式a7109-b7109,则从符号表中获取表达式a7109的类型typeA7109,b7109的类型typeB7109;如果typeA7109或typeB7109为指针类型,则忽略节点s,不进行处理,否则将表达式“a7109-b7109”替换为如下逗号表达式:
(overflowTemp1=(a7109),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7109),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7109)overflowTemp1-(typeB7109)overflowTemp2,
             overflowTemp1-overflowTemp2,fileNameS,lineS,columnS),
(typeA7109)overflowTemp1-(typeB7109)overflowTemp2)
其中overflowTemp1和overflowTemp2为long double类型变量,分别用来记录表达式a7109和表达式b7109的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第12行表达式“temp1-temp2”替换为如下逗号表达式:
(overflowTemp1=(temp1),
overflowStackPush(overflowTemp1),
overflowTemp2=(temp2),
overflowTemp1=overflowStackPop(),
check_overflow((int)overflowTemp1-(int)overflowTemp2,
             overflowTemp1-overflowTemp2,“test.c”,12,15),
(int)overflowTemp1-(int)overflowTemp2)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7110,如果当前节点s为位左移表达式a7110<<b7110,则从符号表中获取表达式a7110的类型typeA7110,b7110的类型typeB7110,将表达式“a7110<<b7110”替换为如下逗号表达式:
(overflowTemp1=(a7110),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7110),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7110)overflowTemp1<<(typeB7110)overflowTemp2,
       (long long int)overflowTemp1<<(long long int)overflowTemp2,
       fileNameS,lineS,columnS),
(typeA7110)overflowTemp1<<(typeB7110)overflowTemp2)
其中overflowTemp1和overflowTemp2为long double类型变量,分别用来记录表达式a7110和表达式b7110的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第13行表达式“temp1<<temp2”替换为如下逗号表达式:
(overflowTemp1=(temp1),
overflowStackPush(overflowTemp1),
overflowTemp2=(temp2),
overflowTemp1=overflowStackPop(),
check_overflow((int)overflowTemp1<<(int)overflowTemp2,
              (long long int)overflowTemp1<<(long long int)overflowTemp2,
              “test.c”,13,15),
(int)overflowTemp1<<(int)overflowTemp2)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7111,如果当前节点s为位右移表达式a7111>>b7111,则从符号表中获取表达式a7111的类型typeA7111,b7111的类型typeB7111,将表达式“a7111>>b7111”替换为如下逗号表达式:
(overflowTemp1=(a7111),
overflowStackPush(overflowTemp1),
overflowTemp2=(b7111),
overflowTemp1=overflowStackPop(),
check_overflow((typeA7111)overflowTemp1>>(typeB7111)overflowTemp2,
      (long long int)overflowTemp1>>(long long int)overflowTemp2,
       fileNameS,lineS,columnS),
(typeA7111)overflowTemp1>>(typeB7111)overflowTemp2)
其中overflowTemp1和overflowTemp2为long double类型变量,分别用来记录表达式a7111和表达式b7111的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第14行表达式“temp1>>temp2”替换为如下逗号表达式:
(overflowTemp1=(temp1),
overflowStackPush(overflowTemp1),
overflowTemp2=(temp2),
overflowTemp1=overflowStackPop(),
check_overflow((int)overflowTemp1>>(int)overflowTemp2,
      (long long int)overflowTemp1>>(long long int)overflowTemp2,
       “test.c”,14,15),
(int)overflowTemp1>>(int)overflowTemp2)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7112,如果当前节点s为复合乘赋值表达式a7112*=b7112,则从符号表中获取表达式a7112的类型typeA7112,b7112的类型typeB7112,将表达式“a7112*=b7112”替换为如下逗号表达式:
(pOverflowTemp=&(a7112),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=(b7112),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7112)((*(typeA7112*)pOverflowTemp)*
(typeB7112)overflowTemp1),(*(typeA7112*)pOverflowTemp)*overflowTemp1,
fileNameS,lineS,columnS),
(*(typeA7112*)pOverflowTemp)*=(typeB7112)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7112的地址,overflowTemp1为long double类型变量,用来记录表达式b7112的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第15行表达式“result*=temp2”替换为如下逗号表达式:
(pOverflowTemp=&(result),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=(temp2),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((int)((*(int*)pOverflowTemp)*(int)overflowTemp1),
         (*(int*)pOverflowTemp)*overflowTemp1,“test.c”,15,9),
(*(int*)pOverflowTemp)*=(int)overflowTemp1)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7113,如果当前节点s为复合除赋值表达式a7113/=b7113,则从符号表中获取表达式a7113的类型typeA7113,b7113的类型typeB7113,将表达式“a7113/=b7113”替换为如下逗号表达式:
(pOverflowTemp=&(a7113),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=(b7113),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7113)((*(typeA7113*)pOverflowTemp)/(typeB7113)
overflowTemp1),(*(typeA7113*)pOverflowTemp)/overflowTemp1,
fileNameS,lineS,columnS),
(*(typeA7113*)pOverflowTemp)/=(typeB7113)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7113的地址,overflowTemp1为long double类型变量,用来记录表达式b7113的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第16行表达式“result/=temp2”替换为逗号表达式,特别地,由于在步骤S6102中对表达式“result/=temp2”已进行了一次转换,所以综合两次操作表达式“result/=temp2”将被替换为:
(pOverflowTemp=&(result),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=((int)check_zero(temp2,“test.c”,16,9)),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((int)((*(int*)pOverflowTemp)/(int)overflowTemp1),
        (*(int*)pOverflowTemp)/overflowTemp1,“test.c”,16,9),
(*(int*)pOverflowTemp)/=(int)overflowTemp1)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7114,如果当前节点s为复合加赋值表达式a7114+=b7114,则从符号表中获取表达式a7114的类型typeA7114,b7114的类型typeB7114;如果typeA7114或typeB7114为指针类型,则忽略节点s,不进行处理,否则将表达式“a7114+=b7114”替换为如下逗号表达式:
(pOverflowTemp=&(a7114),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=(b7114),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7114)((*(typeA7114*)pOverflowTemp)+
(typeB7114)overflowTemp1),
(*(typeA7114*)pOverflowTemp)+overflowTemp1,fileNameS,lineS,columnS),
(*(typeA7114*)pOverflowTemp)+=(typeB7114)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7114的地址,overflowTemp1为long double类型变量,用来记录表达式b7114的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第17行表达式“result+=temp2”替换为如下逗号表达式:
(pOverflowTemp=&(result),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=(temp2),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((int)((*(int*)pOverflowTemp)+(int)overflowTemp1),
       (*(int*)pOverflowTemp)+overflowTemp1,“test.c”,17,9),
(*(int*)pOverflowTemp)+=(int)overflowTemp1)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7115,如果当前节点s为复合减赋值表达式a7115-=b7115,则从符号表中获取表达式a7115的类型typeA7115,b7115的类型typeB7115;如果typeA7115或typeB7115为指针类型,则忽略节点s,不进行处理,否则将表达式“a7115-=b7115”替换为如下逗号表达式:
(pOverflowTemp=&(a7115),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=(b7115),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7115)((*(typeA7115*)pOverflowTemp)-
(typeB7115)overflowTemp1),
(*(typeA7115*)pOverflowTemp)-overflowTemp1,fileNameS,lineS,columnS),
(*(typeA7115*)pOverflowTemp)-=(typeB7115)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7115的地址,overflowTemp1为long double类型变量,用来记录表达式b7115的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第18行表达式“result-=temp2”替换为如下逗号表达式:
(pOverflowTemp=&(result),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=(temp2),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((int)((*(int*)pOverflowTemp)-(int)overflowTemp1),
       (*(int*)pOverflowTemp)-overflowTemp1,“test.c”,18,9),
(*(int*)pOverflowTemp)-=(int)overflowTemp1)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7116,如果当前节点s为复合位左移赋值表达式a7116<<=b7116,则从符号表中获取表达式a7116的类型typeA7116,b7116的类型typeB7116,将表达式“a7116<<=b7116”替换为如下逗号表达式:
(pOverflowTemp=&(a7116),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=(b7116),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7116)((*(typeA7116*)pOverflowTemp)<<
(typeB7116)overflowTemp1),(long long int)(*(typeA7116*)pOverflowTemp)
<<(long long int)overflowTemp1,fileNameS,lineS,columnS),
(*(typeA7116*)pOverflowTemp)<<=(typeB7116)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7116的地址,overflowTemp1为long double类型变量,用来记录表达式b7116的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第19行表达式“result<<=temp2”替换为如下逗号表达式:
(pOverflowTemp=&(result),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=(temp2),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((int)((*(int*)pOverflowTemp)<<(int)overflowTemp1),
(long long int)(*(int*)pOverflowTemp)<<(long long int)overflowTemp1,
“test.c”,19,9),
(*(int*)pOverflowTemp)<<=(int)overflowTemp1)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7117,如果当前节点s为复合位右移赋值表达式a7117>>=b7117,则从符号表中获取表达式a7117的类型typeA7117,b7117的类型typeB7117,将表达式“a7117>>=b7117”替换为如下逗号表达式:
(pOverflowTemp=&(a7117),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=(b7117),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((typeA7117)((*(typeA7117*)pOverflowTemp)>>
(typeB7117)overflowTemp1),(long long int)(*(typeA7117*)pOverflowTemp)>>
(long long int)overflowTemp1,fileNameS,lineS,columnS),
(*(typeA7117*)pOverflowTemp)>>=(typeB7117)overflowTemp1)
其中pOverflowTemp为空类型指针,用来存储表达式a7117的地址,overflowTemp1为long double类型变量,用来记录表达式b7117的值,overflowStackPush和overflowStackPop分别为栈结构的压栈和出栈操作,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第20行表达式“result>>=temp2”替换为如下逗号表达式:
(pOverflowTemp=&(result),
overflowStackPush((long)pOverflowTemp),
overflowTemp1=(temp2),
pOverflowTemp=(void*)(long)overflowStackPop(),
check_overflow((int)((*(int*)pOverflowTemp)>>(int)overflowTemp1),
(long long int)(*(int*)pOverflowTemp)>>(long long int)overflowTemp1,
“test.c”,20,9),
(*(int*)pOverflowTemp)>>=(int)overflowTemp1)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S7118,如果当前节点s为隐含转换表达式(typeCast7118)a7118,其中typeCast7118为隐含转换类型,则从符号表中获取表达式a7118的类型typeA7118;如果typeA7118和typeCast7118相同,忽略节点s,不进行处理,否则将表达式“(typeCast7118)a7118”替换为如下逗号表达式:
(overflowTemp1=(a7118),
check_overflow((typeCast7118)overflowTemp1,
overflowTemp1,fileNameS,lineS,columnS),
(typeCast7118)overflowTemp1)
其中overflowTemp1为long double类型变量,用来记录表达式a7118的值,check_overflow为值溢出检测函数名,fileNameS,lineS,columnS分别为节点s所在文件名,行号和列号;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数声明插入位置集合declLocSet,表示此文件需要值溢出检测相关函数的声明。
本例中,将第21行表达式“2.0”替换为如下逗号表达式:
(overflowTemp1=(2.0),
check_overflow((int)overflowTemp1,overflowTemp1,“test.c”,21,10),
(int)overflowTemp1)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet,表示test.c需要值溢出检测相关函数的声明。
步骤S72,对于包含主函数声明的文件,在文件开始位置插入空类型指针pOverflowTemp,long double类型变量overflowTemp1和overflowTemp2,栈结构struct OverflowStackNode,压栈函数void overflowStackPush(long double num),出栈函数 long double overflowStackPop(),清空栈函数void overflowStackFree()和值溢出检测函数void check_overflow(long double num1,long double num2,const char*fileName,unsigned line,unsigned column)的定义。其中,压栈函数overflowStackPush的参数num代表需要存储的表达式值,检测函数check_overflow的参数num1和num2分别代表类型提升前表达式值和类型提升后表达式值,参数fileName,line,column分别代表运算发生位置所在文件名,行号和列号。检测函数check_overflow对参数num1和num2进行比较:如果两个参数值相同,说明未发生值溢出,不执行任何动作;如果两个参数值不相同,则说明发生了值溢出,报告值溢出错误发生位置的文件名,行号和列号,清空栈并结束程序运行。
本例中,test.c文件包含主函数声明,所以在test.c文件开始位置插入如下定义代码:


步骤S73,根据检测函数声明插入位置集合declLocSet,在相应位置插入空类型指针pOverflowTemp,long double类型变量overflowTemp1和overflowTemp2,栈结构struct OverflowStackNode,压栈函数void overflowStackPush(long double num),出栈函数long double overflowStackPop(),清空栈函数void overflowStackFree()和值溢出检测函数void check_overflow(long double num1,long double num2,const char*fileName,unsigned line,unsigned column)的声明。其中,压栈函数overflowStackPush的参数num代表需要存储的表达式值,检测函数check_overflow的参数num1和num2分别代表类型提升前表达式值和类型提升后表达式值,参数fileName,line,column分别代表运算发生位置所在文件名,行号和列号。然后,将检测函数声明插入位置集合declLocSet重置为空。
本例中,表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet只包含有表示test.c文件开始位置的SourceLocation类型变量loc。所以,在test.c文件开始位置插入声明代码如下:


然后,将表示检测函数声明插入位置集合的set<SourceLocation>类型容器变量declLocSet重置为空。
步骤S8,如果指定需要检测的值计算错误类型中包括变量使用前未初始化错误,则转至步骤S81;否则,略过中间步骤,直接转至步骤S9。
本例中,指定需要检测的值计算错误类型中包括变量使用前未初始化错误,转至步骤S81。
步骤S81,遍历编译器生成的抽象语法树,如果当前节点s所在文件路径不在工作目录下,或已经存在于已处理文件列表中,则忽略该节点,不进行处理。
本例中,遍历test.c对应的抽象语法树,所有节点所在文件路径均在工作目录/tmp/work下,且初始时已处理文件列表set<string>类型容器变量parsedFileSet的元素为空,所以不存在忽略节点的情况。
步骤S8101,如果当前节点s为声明语句,则遍历声明语句中的每一个声明a8101,并通过抽象语法树获得声明a8101的属性;如果声明a8101同时满足如下条件:(1)为变量声明;(2)非全局变量声明;(3)非函数参数声明;(4)声明没有给出初始化表达式,则将变量声明a8101绑定一个编号varIndex;编号从1开始依次选取,所以varIndex也作为记录变量声明总数的计数器。
本例中,第3行的temp3声明同时满足上述条件,将temp3的声明绑定编号1,此时varIndex也为1。
步骤S8102,如果当前节点s为变量声明引用a8102,考察节点s在抽象语法树中的父节点;如果s的父节点为隐含左值向右值转换表达式,自增表达式或自减表达式,忽略节点s,不进行处理,否则,表明节点s为对变量的赋值,利用步骤S8101得到的变量声明和编号的绑定关系,查询得a8102所引用变量声明对应编号indexTemp8102,将表达式“a8102”替换为如下逗号表达式:
*(fileName_set_uninit(indexTemp8102),&(a8102))
其中fileName为节点s所在文件名,并作为fileName_set_uninit的一部分构成变量赋值状态设置函数名;然后,从抽象语法树中获得节点s所在文件的开始位置locS,加入到检测函数定义代码插入位置集合defLocSet,表示此文件需要变量使用前未初始化检测相关函数的定义。
本例中,将第23行的表达式“temp3”替换为如下逗号表达式:
*(test_c_set_uninit(1),&(temp3))
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数定义代码插入位置集合的set<SourceLocation>类型容器变量defLocSet,表示test.c需要变量使用前未初始化检测相关函数的定义。
步骤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,表示此文件需要变量使用前未初始化检测相关函数的定义。
本例中,将第22行的表达式“temp3”替换为如下逗号表达式:
(test_c_check_uninit(1,“test.c”,22,10),temp3)
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数定义代码插入位置集合的set<SourceLocation>类型容器变量defLocSet,表示test.c需要变量使用前未初始化检测相关函数的定义。
步骤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,表示此文件需要变量使用前未初始化检测相关函数的定义。
本例中,将第7行的表达式“temp3”替换为逗号表达式,特别地,由于在步骤S7104中对第7行的表达式“result=--temp3”已进行了一次转换,所以综合两次操作表达式“result=--temp3”将被替换为:
(pOverflowTemp=&(*(test_c_check_uninit(1,“test.c”,7,12),&temp3)),
check_overflow(*(int*)pOverflowTemp-(int)1,
      *(int*)pOverflowTemp-(long double)1,“test.c”,7,10),
(--(*(int*)pOverflowTemp)))
然后,从抽象语法树中获得表示test.c文件开始位置的SourceLocation类型变量loc,加入到表示检测函数定义代码插入位置集合的set<SourceLocation>类型容器变量defLocSet,表示test.c需要变量使用前未初始化检测相关函数的定义。
步骤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的变量声明总数的计数器决定,数组元素初始值均为0;函数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,说明未发生错误,不执行任何动作;如果为0,则说明发生了变量使用前未初始化错误,报告错误发生位置的 文件名,行号和列号,并结束程序运行。
本例中,表示检测函数定义代码插入位置集合的set<SourceLocation>类型容器变量defLocSet只包含有表示test.c文件开始位置的SourceLocation类型变量loc。所以,在test.c文件开始位置插入定义代码如下:

步骤S9,将步骤S6、S7或/和S8中所有替换修改写回到相应的源文件中,并根据本次修改文件更新已处理文件列表,其中,已处理文件列表用于步骤S61,步骤S71,步骤S81中的判断。
本例中,将以上所有替换修改写回到test.c中,并更新表示已处理文件列表set<string>类型容器变量parsedFileSet,将“test.c”字符串作为元素加入其中。
步骤S10,将经过变换的源代码目录或源代码文件按原有方式进行编译,生成可执行文件。
本例中,按原有方式编译test.c,生成可执行文件。
步骤S11,将可执行文件部署在目标平台上并运行,当出现值计算错误时,插入的代码可以自动检测到错误的发生,并准确定位和报告值计算错误在源代码中的位置。
本例中,运行生成的可执行文件,自动检测到值计算错误的发生,并报告在test.c文件的第7行第12列发生使用前未初始化错误。
通过上述实施例可见,使用源代码变换方法,经过上述步骤的操作,在源代码中加入值计算错误自动检测和源代码定位机制,即可准确地在软件运行过程中自动检测和定 位源代码中的值计算错误。
与传统检测技术相比,本实施例提供的值计算错误的自动检测和定位方法有如下优点:
(1)本实施例通过对源代码的抽象语法树进行分析,具有充分的语义信息来判断潜在的值计算错误所在的源文件和代码行,并相应地进行源代码变换,使得在错误检测中可以使用这些位置信息,因此具有更准确的错误定位功能。
(2)本实施例通过源代码变换技术,使得变换后的源代码可以使用原有编译器进行编译和部署,因此具有更好的平台普适性。
(3)本实施例通过对源代码的抽象语法树进行分析,具有充分的语义信息来判断潜在的值计算错误的类型,并相应地进行源代码变换,减少了插入代码段的规模,简化了插入代码段的复杂程度,从而获得了更高的运行时效率和性能。
本实施例可以解决安全关键系统、安全关键应用及常用软件系统中值计算错误检测和定位的难题,能够准确地自动检测和定位错误,实现更好的平台普适性,和更高的运行时性能和效率,从而提高软件开发的质量和软件维护的效率,有良好的社会效益。
以上所述仅是本发明的优选实施方式。应当指出,对于本领域的普通技术人员来说,在不脱离本发明原理的前提下,还可以做出若干优化和改进,或者对其中部分技术特征进行等同替换,这些改进和替换也应视为本发明的保护范围。

一种源代码中值计算错误的自动检测和定位方法.pdf_第1页
第1页 / 共37页
一种源代码中值计算错误的自动检测和定位方法.pdf_第2页
第2页 / 共37页
一种源代码中值计算错误的自动检测和定位方法.pdf_第3页
第3页 / 共37页
点击查看更多>>
资源描述

《一种源代码中值计算错误的自动检测和定位方法.pdf》由会员分享,可在线阅读,更多相关《一种源代码中值计算错误的自动检测和定位方法.pdf(37页珍藏版)》请在专利查询网上搜索。

1、(10)申请公布号 CN 104298594 A (43)申请公布日 2015.01.21 CN 104298594 A (21)申请号 201410499170.9 (22)申请日 2014.09.25 G06F 11/36(2006.01) G06F 21/57(2013.01) (71)申请人 南京航空航天大学 地址 210016 江苏省南京市秦淮区御道街 29 号 (72)发明人 陈哲 朱云龙 魏欧 黄志球 (74)专利代理机构 南京瑞弘专利商标事务所 ( 普通合伙 ) 32249 代理人 杨晓玲 (54) 发明名称 一种源代码中值计算错误的自动检测和定位 方法 (57) 摘要 本发明。

2、公开了一种源代码中值计算错误的自 动检测和定位方法, 属于计算机软件测试领域, 该 方法利用编译器对源代码进行语法分析, 构造抽 象语法树, 通过遍历抽象语法树, 基于表达式类型 和用户指定检测的值计算错误类型, 判断是否存 在值计算错误的潜在风险 ; 对可能产生值计算错 误的表达式进行源代码变换, 加入值计算错误检 测和源代码定位的机制 ; 编译执行变换后的源代 码, 执行后的源代码程序会自动判断值计算错误 的发生, 并准确报告错误对应的源代码位置。 本方 法可以在软件运行过程中自动检测和定位软件中 的值计算错误, 以实现更准确的错误定位功能, 更 好的平台普适性, 更高的运行时性能和效率,。

3、 从而 克服现有的检测方法中存在的技术问题。 (51)Int.Cl. 权利要求书 11 页 说明书 24 页 附图 1 页 (19)中华人民共和国国家知识产权局 (12)发明专利申请 权利要求书11页 说明书24页 附图1页 (10)申请公布号 CN 104298594 A CN 104298594 A 1/11 页 2 1. 一种源代码中值计算错误的自动检测和定位方法, 其特征在于 : 利用编译器对源代 码进行语法分析, 构造抽象语法树, 通过遍历抽象语法树, 基于表达式类型和用户指定检测 的值计算错误类型, 判断是否存在值计算错误的潜在风险 ; 对可能产生值计算错误的表达 式进行源代码变换。

4、, 加入值计算错误检测和源代码定位的机制 ; 编译执行变换后的源代码, 执行后的源代码程序会自动判断值计算错误的发生, 并准确报告错误对应的源代码位置。 2. 根据权利要求 1 所述的源代码中值计算错误的自动检测和定位方法, 其特征在于 : 包括以下步骤 : 步骤 S1, 选择需要变换的源代码目录, 或者单个源代码文件 ; 步骤 S2, 指定需要检测的值计算错误类型 : 除数为 0、 值溢出、 变量使用前未初始化中 的一种或他们之间两种以上的组合 ; 步骤 S3, 将选择的源代码目录或文件复制到源代码变换的工作目录中 ; 步骤 S4, 对工作目录中的所有源文件进行宏扩展处理, 并保存扩展结果到。

5、相应的源文 件中 ; 步骤 S5, 遍历工作目录中的所有源文件, 利用编译器生成符号表和抽象语法树 ; 步骤S6, 如果指定需要检测的值计算错误类型中包括除数为0错误, 则进行除数为0错 误分析和源代码变换计算 ; 步骤 S7, 如果指定需要检测的值计算错误类型中包括值溢出错误, 则进行值溢出错误 分析和源代码变换计算 ; 步骤 S8, 如果指定需要检测的值计算错误类型中包括变量使用前未初始化错误, 则进 行变量使用前未初始化错误分析和源代码变换计算 ; 步骤 S9, 将步骤 S6、 S7 或 / 和 S8 中所有替换修改写回到相应的源文件中, 并根据本次 修改文件更新已处理文件列表 ; 步骤。

6、 S10, 将经过变换的源代码目录或源代码文件按原有方式进行编译, 生成可执行文 件 ; 步骤 S11, 将可执行文件部署在目标平台上并运行, 当出现值计算错误时, 插入的代码 可以自动检测到错误的发生, 并准确定位和报告值计算错误在源代码中的位置。 3. 根据权利要求 2 所述的源代码中值计算错误的自动检测和定位方法, 其特征在于 : 所述步骤 S4 中的宏扩展处理包括 : S41, 利用编译器的词法分析器对文件进行词法分析, 词法分析器返回经过宏扩展处理 之后的词法单元 ; S42, 针对扩展自宏的词法单元, 其属性中包括宏扩展之后的内容和宏扩展的位置, 用 扩展之后的内容替换宏扩展位置的。

7、原有内容。 4. 根据权利要求 3 所述的源代码中值计算错误的自动检测和定位方法, 其特征在于 : 所述步骤 S6 中除数为 0 错误分析和源代码变换计算的方法如下 : 利用函数调用, 在返回除 数给除法表达式之前, 对除数进行检查, 如果除数为 0, 则报告错误发生的源代码位置并结 束程序, 如果除数不为 0, 则正常地将除数返回给除法表达式。 5. 根据权利要求 4 所述的源代码中值计算错误的自动检测和定位方法, 其特征在于 : 所述步骤 S7 中值溢出错误分析和源代码变换计算的方法如下 : 将可能产生值溢出错误的 表达式的操作数进行类型提升, 然后将类型提升后的表达式值和原表达式值进行比。

8、较, 如 权 利 要 求 书 CN 104298594 A 2 2/11 页 3 果相同则说明未发生溢出, 将原表达式值返回, 如果不相同则说明发生溢出, 报告错误发生 的源代码位置并结束程序。 6. 根据权利要求 5 所述的源代码中值计算错误的自动检测和定位方法, 其特征在于 : 所述步骤 S8 中变量使用前未初始化错误分析和源代码变换计算的方法如下 : 记录每一个 非全局且声明时未赋初值的变量的赋值状态, 检查对于变量的引用, 如果是对变量的赋值, 则更新该变量的赋值状态记录, 如果是对变量值的使用, 则检查该变量的赋值状态记录, 未 赋值则表示出现变量使用前未初始化的错误, 已赋值则表示。

9、没有出现该错误。 7. 根据权利要求 6 所述的源代码中值计算错误的自动检测和定位方法, 其特征在于 : 所述步骤 S6 中除数为 0 错误分析和源代码变换计算的方法包括以下步骤 : 步骤 S61, 遍历编译器生成的抽象语法树, 如果当前节点 s 所在文件路径不在工作目录 下, 或已经存在于已处理文件列表中, 则忽略该节点, 不进行处理 ; 步骤 S6101, 如果当前节点 s 为除法表达式 a6101/b6101, 则从符号表中获取表达式 b6101 的类型 typeB6101, 然后将表达式 “a6101/b6101” 替换为如下函数调用 : a6101/(typeB6101)check_。

10、zero(b6101,fi leNameS,lineS,columnS) 其中 check_zero 为除 0 检测函数名, fi leNameS, lineS, columnS 分别为节点 s 所在文 件名, 行号和列号 ; 然后, 从抽象语法树中获得节点 s 所在文件的开始位置 locS, 加入到检 测函数声明插入位置集合 declLocSet, 表示此文件需要除 0 检测相关函数的声明 ; 步骤 S6102, 如果当前节点 s 为复合除赋值表达式 a6102/ b6102, 则从符号表中获取 表达式 b6102 的类型 typeB6102, 然后将表达式 “a6102/ b6102” 替。

11、换为如下函数调用 : a6102/ (typeB6102)check_zero(b6102,fi leNameS,lineS,columnS) 其中 check_zero 为除 0 检测函数名, fi leNameS, lineS, columnS 分别为节点 s 所在文 件名, 行号和列号 ; 然后, 从抽象语法树中获得节点 s 所在文件的开始位置 locS, 加入到检 测函数声明插入位置集合 declLocSet, 表示此文件需要除 0 检测相关函数的声明 ; 步骤 S62, 对于包含主函数声明的文件, 在文件开始位置插入检测函数 long double check_zero(long d。

12、ouble num,const char*fi leName,unsigned line,unsigned column)的 定义, 其中参数num代表除数, 参数fi leName, line, column分别代表运算发生位置所在文件 名, 行号和列号 ; 检测函数check_zero判断表示除数的参数num是否为0, 如果为0, 则报告 除 0 错误发生位置的文件名, 行号和列号, 并结束程序运行, 否则将除数作为函数的返回值 返回 ; 步骤 S63, 根据检测函数声明插入位置集合 declLocSet, 在相应位置插入检测 函数 long double check_zero(long 。

13、double num,const char*fileName,unsigned line,unsigned column) 的声明 ; 其中, 参数 num 代表除数, 参数 fi leName, line, column 分别代表运算发生位置所在文件名, 行号和列号 ; 然后, 将检测函数声明插入位置集合 declLocSet 重置为空。 8. 根据权利要求 7 所述的源代码中值计算错误的自动检测和定位方法, 其特征在于 : 所述步骤 S7 中值溢出错误分析和源代码变换计算的方法包括以下步骤 : 步骤 S71, 遍历编译器生成的抽象语法树, 如果当前节点 s 所在文件路径不在工作目录 下, 。

14、或已经存在于已处理文件列表中, 则忽略该节点, 不进行处理 ; 步骤S7101, 如果当前节点s为后自增表达式a7101+, 则从符号表中获取表达式a7101 权 利 要 求 书 CN 104298594 A 3 3/11 页 4 的类型 typeA7101 ; 如果 typeA7101 为指针类型, 则忽略节点 s, 不进行处理, 否则将表达式 “a7101+” 替换为如下逗号表达式 : (pOverflowTemp &(a7101), check_overflow(*(typeA7101*)pOverflowTemp+(typeA7101)1, *(typeA7101*)pOverflow。

15、Temp+(long double)1,fi leNameS,lineS,columnS), (*(typeA7101*)pOverflowTemp)+) 其中pOverflowTemp为空类型指针, 用来存储表达式a7101的地址, check_overflow为 值溢出检测函数名, fi leNameS, lineS, columnS 分别为节点 s 所在文件名, 行号和列号 ; 然 后, 从抽象语法树中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置 集合 declLocSet, 表示此文件需要值溢出检测相关函数的声明 ; 步骤S7102, 如果当前节点s为后自减。

16、表达式a7102-, 则从符号表中获取表达式a7102 的类型 typeA7102 ; 如果 typeA7102 为指针类型, 则忽略节点 s, 不进行处理, 否则将表达式 “a7102-” 替换为如下逗号表达式 : (pOverflowTemp &(a7102), check_overflow(*(typeA7102*)pOverflowTemp-(typeA7102)1, *(typeA7102*)pOverflowTemp-(long double)1,fi leNameS,lineS,columnS), (*(typeA7102*)pOverflowTemp)-) 其中pOverflo。

17、wTemp为空类型指针, 用来存储表达式a7102的地址, check_overflow为 值溢出检测函数名, fi leNameS, lineS, columnS 分别为节点 s 所在文件名, 行号和列号 ; 然 后, 从抽象语法树中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置 集合 declLocSet, 表示此文件需要值溢出检测相关函数的声明 ; 步骤S7103, 如果当前节点s为前自增表达式+a7103, 则从符号表中获取表达式a7103 的类型 typeA7103 ; 如果 typeA7103 为指针类型, 则忽略节点 s, 不进行处理, 否则将表达式 “。

18、+a7103” 替换为如下逗号表达式 : (pOverflowTemp &(a7103), check_overflow(*(typeA7103*)pOverflowTemp+(typeA7103)1, *(typeA7103*)pOverflowTemp+(long double)1,fi leNameS,lineS,columnS), (+(*(typeA7103*)pOverflowTemp) 其中pOverflowTemp为空类型指针, 用来存储表达式a7103的地址, check_overflow为 值溢出检测函数名, fi leNameS, lineS, columnS 分别为节点。

19、 s 所在文件名, 行号和列号 ; 然 后, 从抽象语法树中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置 集合 declLocSet, 表示此文件需要值溢出检测相关函数的声明 ; 步骤S7104, 如果当前节点s为前自减表达式a7104, 则从符号表中获取表达式a7104 的类型 typeA7104 ; 如果 typeA7104 为指针类型, 则忽略节点 s, 不进行处理, 否则将表达式 “-a7104” 替换为如下逗号表达式 : (pOverflowTemp &(a7104), check_overflow(*(typeA7104*)pOverflowTemp-(。

20、typeA7104)1, *(typeA7104*)pOverflowTemp-(long double)1,fi leNameS,lineS,columnS), (-(*(typeA7104*)pOverflowTemp) 权 利 要 求 书 CN 104298594 A 4 4/11 页 5 其中pOverflowTemp为空类型指针, 用来存储表达式a7104的地址, check_overflow为 值溢出检测函数名, fi leNameS, lineS, columnS 分别为节点 s 所在文件名, 行号和列号 ; 然 后, 从抽象语法树中获得节点 s 所在文件的开始位置 locS, 。

21、加入到检测函数声明插入位置 集合 declLocSet, 表示此文件需要值溢出检测相关函数的声明 ; 步骤 S7105, 如果当前节点 s 为取负表达式 -a7105, 则从符号表中获取表达式 a7105 的 类型 typeA7105, 将表达式 “-a7105” 替换为如下逗号表达式 : (overflowTemp1 (a7105), check_overflow(-(typeA7105)overflowTemp1, -overflowTemp1,fi leNameS,lineS,columnS), -(typeA7105)overflowTemp1) 其中 overflowTemp1 为 。

22、long double 类型变量, 用来记录表达式 a7105 的值, check_ overflow 为值溢出检测函数名, fi leNameS, lineS, columnS 分别为节点 s 所在文件名, 行号 和列号 ; 然后, 从抽象语法树中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明 插入位置集合 declLocSet, 表示此文件需要值溢出检测相关函数的声明 ; 步骤 S7106, 如果当前节点 s 为乘法表达式 a7106*b7106, 则从符号表中获取表达式 a7106 的类型 typeA7106, b7106 的类型 typeB7106, 将表达式 “a7。

23、106*b7106” 替换为如下逗 号表达式 : (overflowTemp1 (a7106), overflowStackPush(overflowTemp1), overflowTemp2 (b7106), overflowTemp1 overflowStackPop(), check_overflow(typeA7106)overflowTemp1*(typeB7106)overflowTemp2, overflowTemp1*overflowTemp2,fi leNameS,lineS,columnS), (typeA7106)overflowTemp1*(typeB7106)over。

24、flowTemp2) 其中 overflowTemp1 和 overflowTemp2 为 long double 类型变量, 分别用来记录表达 式 a7106 和表达式 b7106 的值, overflowStackPush 和 overflowStackPop 分别为栈结构的 压栈和出栈操作, check_overflow 为值溢出检测函数名, fi leNameS, lineS, columnS 分别 为节点 s 所在文件名, 行号和列号 ; 然后, 从抽象语法树中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置集合 declLocSet, 表示此文件需要值溢出检。

25、测相关函 数的声明 ; 步骤 S7107, 如果当前节点 s 为除法表达式 a7107/b7107, 则从符号表中获取表达式 a7107 的类型 typeA7107, b7107 的类型 typeB7107, 将表达式 “a7107/b7107” 替换为如下逗 号表达式 : (overflowTemp1 (a7107), overflowStackPush(overflowTemp1), overflowTemp2 (b7107), overflowTemp1 overflowStackPop(), check_overflow(typeA7107)overflowTemp1/(typeB71。

26、07)overflowTemp2, overflowTemp1/overflowTemp2,fi leNameS,lineS,columnS), 权 利 要 求 书 CN 104298594 A 5 5/11 页 6 (typeA7107)overflowTemp1/(typeB7107)overflowTemp2) 其中 overflowTemp1 和 overflowTemp2 为 long double 类型变量, 分别用来记录表达 式 a7107 和表达式 b7107 的值, overflowStackPush 和 overflowStackPop 分别为栈结构的 压栈和出栈操作, c。

27、heck_overflow 为值溢出检测函数名, fi leNameS, lineS, columnS 分别 为节点 s 所在文件名, 行号和列号 ; 然后, 从抽象语法树中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置集合 declLocSet, 表示此文件需要值溢出检测相关函 数的声明 ; 步骤 S7108, 如果当前节点 s 为加法表达式 a7108+b7108, 则从符号表中获取表达式 a7108 的类型 typeA7108, b7108 的类型 typeB7108 ; 如果 typeA7108 或 typeB7108 为指针类 型, 则忽略节点 s, 不进行。

28、处理, 否则将表达式 “a7108+b7108” 替换为如下逗号表达式 : (overflowTemp1 (a7108), overflowStackPush(overflowTemp1), overflowTemp2 (b7108), overflowTemp1 overflowStackPop(), check_overflow(typeA7108)overflowTemp1+(typeB7108)overflowTemp2, overflowTemp1+overflowTemp2,fi leNameS,lineS,columnS), (typeA7108)overflowTemp1+(t。

29、ypeB7108)overflowTemp2) 其中 overflowTemp1 和 overflowTemp2 为 long double 类型变量, 分别用来记录表达 式 a7108 和表达式 b7108 的值, overflowStackPush 和 overflowStackPop 分别为栈结构的 压栈和出栈操作, check_overflow 为值溢出检测函数名, fi leNameS, lineS, columnS 分别 为节点 s 所在文件名, 行号和列号 ; 然后, 从抽象语法树中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置集合 declLocSet。

30、, 表示此文件需要值溢出检测相关函 数的声明 ; 步骤 S7109, 如果当前节点 s 为减法表达式 a7109-b7109, 则从符号表中获取表达式 a7109 的类型 typeA7109, b7109 的类型 typeB7109 ; 如果 typeA7109 或 typeB7109 为指针类 型, 则忽略节点 s, 不进行处理, 否则将表达式 “a7109-b7109” 替换为如下逗号表达式 : (overflowTemp1 (a7109), overflowStackPush(overflowTemp1), overflowTemp2 (b7109), overflowTemp1 ove。

31、rflowStackPop(), check_overflow(typeA7109)overflowTemp1-(typeB7109)overflowTemp2, overflowTemp1-overflowTemp2,fi leNameS,lineS,columnS), (typeA7109)overflowTemp1-(typeB7109)overflowTemp2) 其中 overflowTemp1 和 overflowTemp2 为 long double 类型变量, 分别用来记录表达 式 a7109 和表达式 b7109 的值, overflowStackPush 和 overflo。

32、wStackPop 分别为栈结构的 压栈和出栈操作, check_overflow 为值溢出检测函数名, fi leNameS, lineS, columnS 分别 为节点 s 所在文件名, 行号和列号 ; 然后, 从抽象语法树中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置集合 declLocSet, 表示此文件需要值溢出检测相关函 数的声明 ; 权 利 要 求 书 CN 104298594 A 6 6/11 页 7 步骤S7110, 如果当前节点s为位左移表达式a7110b7111, 则从符号表中获取表达式 a7111 的类型 typeA7111, b7111 的。

33、类型 typeB7111, 将表达式 “a7111b7111” 替换为如下 逗号表达式 : (overflowTemp1 (a7111), overflowStackPush(overflowTemp1), overflowTemp2 (b7111), overflowTemp1 overflowStackPop(), check_overflow(typeA7111)overflowTemp1(typeB7111)overflowTemp2, (long long int)overflowTemp1(long long int)overflowTemp2, fi leNameS,lineS,。

34、columnS), (typeA7111)overflowTemp1(typeB7111)overflowTemp2) 其中 overflowTemp1 和 overflowTemp2 为 long double 类型变量, 分别用来记录表达 式 a7111 和表达式 b7111 的值, overflowStackPush 和 overflowStackPop 分别为栈结构的 压栈和出栈操作, check_overflow 为值溢出检测函数名, fi leNameS, lineS, columnS 分别 为节点 s 所在文件名, 行号和列号 ; 然后, 从抽象语法树中获得节点 s 所在文件的开。

35、始位置 locS, 加入到检测函数声明插入位置集合 declLocSet, 表示此文件需要值溢出检测相关函 数的声明 ; 步骤 S7112, 如果当前节点 s 为复合乘赋值表达式 a7112* b7112, 则从符号表中获取 表达式 a7112 的类型 typeA7112, b7112 的类型 typeB7112, 将表达式 “a7112* b7112” 替 换为如下逗号表达式 : (pOverflowTemp &(a7112), overflowStackPush(long)pOverflowTemp), 权 利 要 求 书 CN 104298594 A 7 7/11 页 8 overflo。

36、wTemp1 (b7112), pOverflowTemp (void*)(long)overflowStackPop(), check_overflow(typeA7112)(*(typeA7112*)pOverflowTemp)* (typeB7112)overflowTemp1),(*(typeA7112*)pOverflowTemp)*overflowTemp1, fi leNameS,lineS,columnS), (*(typeA7112*)pOverflowTemp)* (typeB7112)overflowTemp1) 其中 pOverflowTemp 为空类型指针, 用来存储。

37、表达式 a7112 的地址, overflowTemp1 为 long double 类 型 变 量,用 来 记 录 表 达 式 b7112 的 值, overflowStackPush 和 overflowStackPop 分别为栈结构的压栈和出栈操作, check_overflow 为值溢出检测函数 名, fi leNameS, lineS, columnS 分别为节点 s 所在文件名, 行号和列号 ; 然后, 从抽象语法树 中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置集合 declLocSet, 表示此文件需要值溢出检测相关函数的声明 ; 步骤 S7113,。

38、 如果当前节点 s 为复合除赋值表达式 a7113/ b7113, 则从符号表中获取 表达式 a7113 的类型 typeA7113, b7113 的类型 typeB7113, 将表达式 “a7113/ b7113” 替 换为如下逗号表达式 : (pOverflowTemp &(a7113), overflowStackPush(long)pOverflowTemp), overflowTemp1 (b7113), pOverflowTemp (void*)(long)overflowStackPop(), check_overflow(typeA7113)(*(typeA7113*)pOve。

39、rflowTemp)/(typeB7113) overflowTemp1),(*(typeA7113*)pOverflowTemp)/overflowTemp1, fi leNameS,lineS,columnS), (*(typeA7113*)pOverflowTemp)/ (typeB7113)overflowTemp1) 其中 pOverflowTemp 为空类型指针, 用来存储表达式 a7113 的地址, overflowTemp1 为 long double 类 型 变 量,用 来 记 录 表 达 式 b7113 的 值, overflowStackPush 和 overflowSt。

40、ackPop 分别为栈结构的压栈和出栈操作, check_overflow 为值溢出检测函数 名, fi leNameS, lineS, columnS 分别为节点 s 所在文件名, 行号和列号 ; 然后, 从抽象语法树 中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置集合 declLocSet, 表示此文件需要值溢出检测相关函数的声明 ; 步骤 S7114, 如果当前节点 s 为复合加赋值表达式 a7114+ b7114, 则从符号表中获取 表达式 a7114 的类型 typeA7114, b7114 的类型 typeB7114 ; 如果 typeA7114 或 t。

41、ypeB7114 为指针类型, 则忽略节点 s, 不进行处理, 否则将表达式 “a7114+ b7114” 替换为如下逗号 表达式 : (pOverflowTemp &(a7114), overflowStackPush(long)pOverflowTemp), overflowTemp1 (b7114), pOverflowTemp (void*)(long)overflowStackPop(), check_overflow(typeA7114)(*(typeA7114*)pOverflowTemp)+ (typeB7114)overflowTemp1), 权 利 要 求 书 CN 104。

42、298594 A 8 8/11 页 9 (*(typeA7114*)pOverflowTemp)+overflowTemp1,fi leNameS,lineS,columnS), (*(typeA7114*)pOverflowTemp)+ (typeB7114)overflowTemp1) 其中 pOverflowTemp 为空类型指针, 用来存储表达式 a7114 的地址, overflowTemp1 为 long double 类 型 变 量,用 来 记 录 表 达 式 b7114 的 值, overflowStackPush 和 overflowStackPop 分别为栈结构的压栈和出栈。

43、操作, check_overflow 为值溢出检测函数 名, fi leNameS, lineS, columnS 分别为节点 s 所在文件名, 行号和列号 ; 然后, 从抽象语法树 中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置集合 declLocSet, 表示此文件需要值溢出检测相关函数的声明 ; 步骤 S7115, 如果当前节点 s 为复合减赋值表达式 a7115- b7115, 则从符号表中获取 表达式 a7115 的类型 typeA7115, b7115 的类型 typeB7115 ; 如果 typeA7115 或 typeB7115 为指针类型, 则忽略。

44、节点 s, 不进行处理, 否则将表达式 “a7115- b7115” 替换为如下逗号 表达式 : (pOverflowTemp &(a7115), overflowStackPush(long)pOverflowTemp), overflowTemp1 (b7115), pOverflowTemp (void*)(long)overflowStackPop(), check_overflow(typeA7115)(*(typeA7115*)pOverflowTemp)- (typeB7115)overflowTemp1), (*(typeA7115*)pOverflowTemp)-overfl。

45、owTemp1,fi leNameS,lineS,columnS), (*(typeA7115*)pOverflowTemp)- (typeB7115)overflowTemp1) 其中 pOverflowTemp 为空类型指针, 用来存储表达式 a7115 的地址, overflowTemp1 为 long double 类 型 变 量,用 来 记 录 表 达 式 b7115 的 值, overflowStackPush 和 overflowStackPop 分别为栈结构的压栈和出栈操作, check_overflow 为值溢出检测函数 名, fi leNameS, lineS, colum。

46、nS 分别为节点 s 所在文件名, 行号和列号 ; 然后, 从抽象语法树 中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置集合 declLocSet, 表示此文件需要值溢出检测相关函数的声明 ; 步骤 S7116, 如果当前节点 s 为复合位左移赋值表达式 a7116 b7117, 则从符号表 中获取表达式 a7117 的类型 typeA7117, b7117 的类型 typeB7117, 将表达式 “a7117 b7117” 替换为如下逗号表达式 : (pOverflowTemp &(a7117), overflowStackPush(long)pOverflowT。

47、emp), overflowTemp1 (b7117), pOverflowTemp (void*)(long)overflowStackPop(), check_overflow(typeA7117)(*(typeA7117*)pOverflowTemp) (typeB7117)overflowTemp1),(long long int)(*(typeA7117*)pOverflowTemp) (long long int)overflowTemp1,fi leNameS,lineS,columnS), (*(typeA7117*)pOverflowTemp) (typeB7117)over。

48、flowTemp1) 其中 pOverflowTemp 为空类型指针, 用来存储表达式 a7117 的地址, overflowTemp1 为 long double 类 型 变 量,用 来 记 录 表 达 式 b7117 的 值, overflowStackPush 和 overflowStackPop 分别为栈结构的压栈和出栈操作, check_overflow 为值溢出检测函数 名, fi leNameS, lineS, columnS 分别为节点 s 所在文件名, 行号和列号 ; 然后, 从抽象语法树 中获得节点 s 所在文件的开始位置 locS, 加入到检测函数声明插入位置集合 dec。

49、lLocSet, 表示此文件需要值溢出检测相关函数的声明 ; 步 骤 S7118, 如 果 当 前 节 点 s 为 隐 含 转 换 表 达 式 (typeCast7118)a7118, 其 中 typeCast7118 为隐含转换类型, 则从符号表中获取表达式 a7118 的类型 typeA7118 ; 如果 typeA7118和typeCast7118相同, 忽略节点s, 不进行处理, 否则将表达式 “(typeCast7118) a7118” 替换为如下逗号表达式 : (overflowTemp1 (a7118), check_overflow(typeCast7118)overflowTemp1, overflowTemp1,fi leNameS,lineS,columnS), (typeCast7118)overflowTemp1) 其中 overflowTemp1 为 long double 类型变量, 用来记录表达式 a7118 的值, check_ overflow 为值溢出。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 物理 > 计算;推算;计数


copyright@ 2017-2020 zhuanlichaxun.net网站版权所有
经营许可证编号:粤ICP备2021068784号-1