《数组越界错误的自动检测和校正方法.pdf》由会员分享,可在线阅读,更多相关《数组越界错误的自动检测和校正方法.pdf(25页珍藏版)》请在专利查询网上搜索。
1、(10)申请公布号 CN 103778061 A (43)申请公布日 2014.05.07 CN 103778061 A (21)申请号 201410022323.0 (22)申请日 2014.01.17 G06F 11/36(2006.01) (71)申请人 南京航空航天大学 地址 210016 江苏省南京市秦淮区御道街 29 号 (72)发明人 陈哲 李文明 黄志球 (74)专利代理机构 南京经纬专利商标代理有限 公司 32200 代理人 朱小兵 刘谦 (54) 发明名称 数组越界错误的自动检测和校正方法 (57) 摘要 本发明提供一种数组越界错误的自动检测 和校正方法, 包括 : 选择待。
2、变换的源代码 ; 利用编 译器生成源代码的符号表和抽象语法树 ; 遍历抽 象语法树, 构造指针依赖图, 并进行源代码变换 计算 ; 在源代码中将需替换的部分源代码进行替 换 ; 将按照数组越界检测策略和校正策略生成的 函数定义写入变换后源代码的开头部分 ; 将变换 后的源代码用原编译器进行编译 ; 把生成的可执 行文件部署到目标系统并运行, 自动检测和校正 数组越界错误, 并准确报告错误对应的源代码位 置。本发明提供的数组越界错误的自动检测和校 正方法具有更准确的错误定位功能, 更好的运行 时效率和性能, 更自动化的运行时错误校正功能。 (51)Int.Cl. 权利要求书 4 页 说明书 19。
3、 页 附图 1 页 (19)中华人民共和国国家知识产权局 (12)发明专利申请 权利要求书4页 说明书19页 附图1页 (10)申请公布号 CN 103778061 A CN 103778061 A 1/4 页 2 1. 一种数组越界错误的自动检测和校正方法, 其特征在于, 包括 : 步骤 1、 选择待变换的源代码项目目录, 或者单个源代码文件 ; 步骤 2、 针对待变换的源代码, 利用编译器生成源代码的符号表和抽象语法树 ; 步骤 3、 遍历抽象语法树中的所有结点, 构造指针依赖图, 并进行源代码变换计算, 其 中 : 所述指针依赖图是一个有向图二元组, 所述有向图二元组包括源代码中的指针集。
4、合和 源代码中的指针依赖关系集合, 所述源代码中的指针集合构成指针依赖图中的结点集合, 所述源代码中的指针依赖关系集合构成指针依赖图中的有向边集合 ; 步骤 4、 根据步骤 3 的计算结果, 在源代码中将需替换的部分源代码进行替换, 生成变 换后的源代码, 并保存到新项目目录或新文件 ; 步骤 5、 定义数组越界检测策略和校正策略, 并将这些策略转化为函数 _MNT_CHK_AAV 的定义, 将按照策略生成的函数 _MNT_CHK_AAV 的定义写入变换后源代码的开头部分 ; 步骤 6、 将变换后的项目目录或文件用原编译器进行编译, 生成目标系统上的可执行文 件 ; 步骤 7、 将生成的可执行。
5、文件部署到目标系统并运行, 当可执行文件运行到已替换或插 入的代码段时, 将自动检测和校正数组越界错误, 并准确报告错误对应的源代码位置。 2. 如权利要求 1 所述的数组越界错误的自动检测和校正方法, 其特征在于, 所述遍历 抽象语法树中的所有结点, 构造指针依赖图, 并进行源代码变换计算, 进一步包括 : 在遍历抽象语法树的过程中, 根据当前遍历到的结点 s 的类型进行如下操作之一 : 向指针依赖图中加入指针依赖关系, 将数组下标访问表达式和指针访问表达式替换为 _MNT_CHK_AAV 函数的调用, 将函数声明、 函数定义、 函数调用表达式替换为新的表达式。 3. 如权利要求 1 所述的。
6、数组越界错误的自动检测和校正方法, 其特征在于, 所述在遍 历抽象语法树的过程中, 根据当前遍历到的结点 s 的类型进行如下操作之一 : 向指针依赖 图中加入指针依赖关系, 将数组下标访问表达式和指针访问表达式替换为 _MNT_CHK_AAV 函数的调用, 将函数声明、 函数定义、 函数调用表达式替换为新的表达式, 进一步包括 : 在遍历抽象语法树的过程中, 对于当前遍历到的结点 s, 得到其所在的源文件名 filename 和代码行号 loc, 并根据当前遍历到的结点 s 的类型分别进行如下操作 : 操作1、 如果结点s是一个带初始值的指针声明type*p=expr, 其中p为指针名, ex。
7、pr为 表达式, 且 expr 中包含一个支配指针 q, 则将指针对 (p,q) 作为一条边加入指针依赖图 ; 操作 2、 如果结点 s 是一个指针赋值表达式 p=expr, 其中 p 为指针名, expr 为表达式, 且 expr 中包含一个支配指针 q, 则将 (p,q) 作为一条边加入指针依赖图 ; 操作3、 如果结点s是一个数组下标表达式pexpr, 其中p为指针名或数组名, expr为 表达式, 则根据 p 的类型分别进行如下操作 : 操作 31、 如果 p 是符号表中已定义的一个数组, 则从符号表中获取该数组的类型 type 和长度 len, 然后将该表达式替换为如下函数调用 : 。
8、*(type*)(_MNT_CHECK_AAV(p+expr,p,p+len,filename,loc) 其中, 函数参数 p+expr 表示数组下标表达式访问的内存地址, 函数参数 p 表示数组的 起始地址, 函数参数p+len表示数组的结束地址, 函数参数filename表示源文件名, 函数参 数 loc 表示代码行号 ; 权 利 要 求 书 CN 103778061 A 2 2/4 页 3 操作 32、 如果 p 是所在函数声明的第 n 个形式参数, 则从符号表中获取该指针的类型 type, 然后将该表达式替换为如下函数调用 : *(type*)(_MNT_CHK_AAV(p+expr,。
9、_MNT_CHK_AAV_B_n,_MNT_CHK_AAV_E_ n,filename,loc) 其中, 函数参数 p+expr 表示数组下标表达式访问的内存地址, 函数参数 _MNT_CHK_ AAV_B_n表示第n个形式参数的起始地址, 函数参数_MNT_CHK_AAV_E_n表示第n个形式参 数的结束地址, 函数参数 filename 表示源文件名, 函数参数 loc 表示代码行号 ; 操作 33、 如果 p 是不满足以上操作 31、 操作 32 中的两种情况的指针, 则从指针依赖图 中获取其最终依赖指针 q, 如果 q 不存在, 则认为源代码中存在指针使用前未赋初值的错 误, 并报错,。
10、 如果 q 存在, 则根据 q 的类型分别进行如下操作 : 操作 331、 如果 q 是符号表中已定义的一个数组, 则从符号表中获取指针 p 的类型 type 和数组 q 的长度 len, 然后将该表达式替换为如下函数调用 : *(type*)(_MNT_CHECK_AAV(p+expr,q,q+len,filename,loc) 其中, 函数参数 p+expr 表示数组下标表达式访问的内存地址, 函数参数 q 表示数组的 起始地址, 函数参数q+len表示数组的结束地址, 函数参数filename表示源文件名, 函数参 数 loc 表示代码行号 ; 操作 332、 如果 q 是所在函数声明的。
11、第 n 个形式参数, 则从符号表中获取指针 p 的类型 type, 然后将该表达式替换为如下函数调用 : *(type*)(_MNT_CHK_AAV(p+expr,_MNT_CHK_AAV_B_n,_MNT_CHK_AAV_E_ n,filename,loc) 其中, 函数参数 p+expr 表示数组下标表达式访问的内存地址, 函数参数 _MNT_CHK_ AAV_B_n表示第n个形式参数的起始地址, 函数参数_MNT_CHK_AAV_E_n表示第n个形式参 数的结束地址, 函数参数 filename 表示源文件名, 函数参数 loc 表示代码行号 ; 操作 333、 如果 q 是不满足以上操。
12、作 331、 操作 332 中的两种情况的指针, 则认为源代码 中存在指针使用前未赋初值的错误, 并报错 ; 操作 4、 如果结点 s 是一个指针访问表达式 *expr, 其中 expr 为表达式, 且 expr 中包含 一个支配指针 p, 则根据 p 的类型分别进行如下操作 : 操作 41、 如果 p 是符号表中已定义的一个数组, 则从符号表中获取该数组的类型 type 和长度 len, 然后将该表达式替换为如下函数调用 : *(type*)(_MNT_CHECK_AAV(expr,p,p+len,filename,loc) 其中, 函数参数 expr 表示指针访问表达式访问的内存地址, 函。
13、数参数 p 表示数组的起 始地址, 函数参数p+len表示数组的结束地址, 函数参数filename表示源文件名, 函数参数 loc 表示代码行号 ; 操作 42、 如果 p 是所在函数声明的第 n 个形式参数, 则从符号表中获取该指针的类型 type, 然后将该表达式替换为如下函数调用 : *(type*)(_MNT_CHK_AAV(expr,_MNT_CHK_AAV_B_n,_MNT_CHK_AAV_E_ n,filename,loc) 其中, 函数参数 expr 表示指针访问表达式访问的内存地址, 函数参数 _MNT_CHK_AAV_ B_n表示第n个形式参数的起始地址, 函数参数_MN。
14、T_CHK_AAV_E_n表示第n个形式参数的 权 利 要 求 书 CN 103778061 A 3 3/4 页 4 结束地址, 函数参数 filename 表示源文件名, 函数参数 loc 表示代码行号 ; 操作 43、 如果 p 是不满足以上操作 41、 操作 42 中的两种情况的指针, 则从指针依赖图 中获取其最终依赖指针 q, 如果 q 不存在, 则认为源代码中存在指针使用前未赋初值的错 误, 并报错, 如果 q 存在, 则根据 q 的类型分别进行如下操作 : 操作 431、 如果 q 是符号表中已定义的一个数组, 则从符号表中获取指针 p 的类型 type 和数组 q 的长度 len。
15、, 然后将该表达式替换为如下函数调用 : *(type*)(_MNT_CHECK_AAV(expr,q,q+len,filename,loc) 其中, 函数参数 expr 表示指针访问表达式访问的内存地址, 函数参数 q 表示数组的起 始地址, 函数参数q+len表示数组的结束地址, 函数参数filename表示源文件名, 函数参数 loc 表示代码行号 ; 操作 432、 如果 q 是所在函数声明的第 n 个形式参数, 则从符号表中获取指针 p 的类型 type, 然后将该表达式替换为如下函数调用 : *(type*)(_MNT_CHK_AAV(expr,_MNT_CHK_AAV_B_n,_。
16、MNT_CHK_AAV_E_ n,filename,loc) 其中, 函数参数 expr 表示指针访问表达式访问的内存地址, 函数参数 _MNT_CHK_AAV_ B_n表示第n个形式参数的起始地址, 函数参数_MNT_CHK_AAV_E_n表示第n个形式参数的 结束地址, 函数参数 filename 表示源文件名, 函数参数 loc 表示代码行号 ; 操作 433、 如果 q 是不满足以上操作 431、 操作 432 中的两种情况的指针, 则认为源代码 中存在指针使用前未赋初值的错误, 并报错 ; 操作 5、 如果结点 s 是一个函数声明或函数定义表达式 type func(,type_ne。
17、xpr_ n,), 其中 : 第 n 个参数表达式 expr_n 为 type_n 类型的数组或指针声明 p, 省略号表示 其它参数表达式, 则将该函数声明或函数定义替换为如下函数 : type func(,type_n expr_n,void*_MNT_CHK_AAV_B_n,void*_MNT_CHK_AAV_E_ n,) 其中, 省略号表示原来的所有参数表达式, 函数参数 _MNT_CHK_AAV_B_n 表示第 n 个参数表达式的起始地址, 函数参数 _MNT_CHK_AAV_E_n 表示第 n 个参数表达式的结束地 址 ; 操作 6、 如果结点 s 是一个函数调用表达式 func(,。
18、expr_n,), 其中 : 第 n 个参数表 达式expr_n中包含一个支配指针p, 省略号表示其它参数表达式, 则根据p的类型分别进 行如下操作 : 操作 61、 如果 p 是符号表中已定义的一个数组, 则从符号表中获取该数组的长度 len, 然后将该表达式替换为如下函数调用 : func(,expr_n,p,p+len,), 其中, 省略号表示 原来的所有参数表达式, 函数参数p表示数组的起始地址, 函数参数p+len表示数组的结束 地址 ; 操作 62、 如果 p 是所在函数声明的第 n 个形式参数, 则将该表达式替换为如下函数调 用 : func(,expr_n,_MNT_CHK_A。
19、AV_B_n,_MNT_CHK_AAV_E_n,) 其中, 省略号表示原来的所有参数表达式, 函数参数_MNT_CHK_AAV_B_n表示第n个 形式参数的起始地址, 函数参数 _MNT_CHK_AAV_E_n 表示第 n 个形式参数的结束地址 ; 权 利 要 求 书 CN 103778061 A 4 4/4 页 5 操作 63、 如果 p 是不满足以上操作 61、 操作 62 中的两种情况的指针, 则从指针依赖图 中获取其最终依赖指针 q, 如果 q 不存在, 则认为源代码中存在指针使用前未赋初值的错 误, 并报错, 如果 q 存在, 则根据 q 的类型分别进行如下操作 : 操作 631、 。
20、如果 q 是符号表中已定义的一个数组, 则从符号表中获取数组 q 的长度 len, 然后将该表达式替换为如下函数调用 : func(,expr_n,q,q+len,), 其中, 省略号表示 原来的所有参数表达式, 函数参数q表示数组的起始地址, 函数参数q+len表示数组的结束 地址 ; 操作 632、 如果 q 是所在函数声明的第 n 个形式参数, 则将该表达式替换为如下函数调 用 : func(,expr_n,_MNT_CHK_AAV_B_n,_MNT_CHK_AAV_E_n,) 其中, 省略号表示原来的所有参数表达式, 函数参数_MNT_CHK_AAV_B_n表示第n个 形式参数的起始地。
21、址, 函数参数 _MNT_CHK_AAV_E_n 表示第 n 个形式参数的结束地址 ; 操作 633、 如果 q 是不满足以上操作 631、 操作 632 中的两种情况的指针, 则认为源代码 中存在指针使用前未赋初值的错误, 并报错。 4.如权利要求1所述的数组越界错误的自动检测和校正方法, 其特征在于, 所述步骤3 进一步包括 : 在指针依赖图中, 从 p 开始沿有向边往前遍历, 直到访问到一个没有后继结点的指针 q, 那么 q 就是 p 的最终依赖指针。 5.如权利要求1所述的数组越界错误的自动检测和校正方法, 其特征在于, 所述步骤3 进一步包括 : 支配指针是指决定该表达式指向地址的主。
22、要指针变量 ; 该表达式的其他部分决定相对于该指针指向地址的偏移量。 6. 如权利要求 1 所述的数组越界错误的自动检测和校正方法, 其特征在于, 所述检测 策略包括 : 判断要访问的地址p是否在允许的范围begin,end)之间, 如果超出该范围, 则报告数 组越界错误。 7. 如权利要求 1 所述的数组越界错误的自动检测和校正方法, 其特征在于 : 所述校正 策略包括 : 当合法的内存范围为 begin,end), 大小为 n 时, 如果访问地址 p 为下越界, 则将 p 和 begin 之间的偏移量进行模 n 运算, 并被 end 减后 作为映射的合法访问地址 ; 如果访问地址 p 为上。
23、越界, 则将 p 和 end 之间的偏移量进行模 n 运算, 并加上 begin 作 为映射的合法访问地址 ; 如果访问地址 p 在 begin,end) 范围内, 则不作任何计算。 8.如权利要求1所述的数组越界错误的自动检测和校正方法, 其特征在于 : 所述步骤5 进一步包括 : 检测策略和校正策略直接通过源代码的方式说明 ; 或者, 使用特别定义的描述语言来说明, 并通过语言自动转化工具自动翻译为源代码。 权 利 要 求 书 CN 103778061 A 5 1/19 页 6 数组越界错误的自动检测和校正方法 技术领域 0001 本发明涉及计算机软件测试和校正技术领域, 特别涉及一种数组。
24、越界错误的自动 检测和校正方法。 背景技术 0002 缓冲区溢出是一种非常危险的软件漏洞, 并广泛存在于各种应用软件中。缓冲区 溢出漏洞可能导致软件行为异常、 内存访问错误或系统崩溃, 也可被黑客用来攻击有价值 的软件系统。 目前, 缓冲区溢出问题已经成为造成软件漏洞的主要原因。 例如, 根据US-CERT 漏洞数据库统计资料可知, 在 20 个最严重的漏洞中, 就有 11 个是由缓冲区溢出引起。尤其 对于那些用于控制安全关键工业系统的嵌入式控制软件 (例如, 飞行控制软件、 高速列车控 制软件、 核电站控制软件等) 和安全关键应用软件系统 (例如, 银行交易软件、 网上交易软件 等) , 当。
25、因缓冲区溢出漏洞引起软件失效、 系统故障或黑客攻击, 损失将非常惨重。因此, 有 效的缓冲区溢出检测和校正技术是软件研发和维护中的重要问题。 0003 软件中缓冲区的内存分配包括两种方式 : 静态内存分配和动态内存分配。静态内 存分配主要指源代码中变量和数组的定义, 而动态内存分配主要指使用 malloc 等内存管 理函数为软件分配的堆空间。通常, 不带操作系统或内存管理模块的嵌入式工业控制系统 不支持动态内存分配。 因此, 在这样的系统中, 数组越界访问成为了缓冲区溢出的主要表现 形式。也就是说, 检测和校正软件中的数组越界错误是避免缓冲区溢出的主要方式。 0004 目前, 现有的检测数组越。
26、界错误的方法分为两种类型 : 静态方法和动态方法。 0005 静态方法是指通过分析软件设计模型或者源代码来检验错误的方法, 而不需要实 际运行该软件。 除人工代码走查之外, 静态方法的一个主流技术是模型检验技术, 例如SPIN 模型检验器等。 模型检验工具一般通过抽象建模, 运行验证, 生成和分析反例等步骤来检验 设计模型的正确性。例如, 业内曾经使用 SPIN 模型检验器对某型国产飞机的飞行控制系 统的缓冲区控制模块的设计模型进行了验证, 准确地找出了由模块间复杂交互行为引起的 数组越界错误。 模型检验技术的优点在于, 可以对软件所有可能的行为进行穷举搜索, 确保 结果的完备性。然而, 该技。
27、术的不足之处在于 : 1、 由于模型检验技术本身的计算复杂性是 PSPACE 完全的, 因此它与生俱来的状态爆炸问题使得该技术很难直接被应用于较大规模软 件的验证, 例如超过 10000 行代码的软件 ; 2、 由于模型检验技术通常是对软件系统抽象出 来的设计模型进行验证, 而不是全部源代码, 所以无法确保该软件的实际实现是正确的, 即 无法确保源代码的正确性。 0006 动态方法是指通过运行软件, 并在软件运行过程中检测错误的方法。动态方法的 一个主流技术是软件测试技术。软件测试工具一般通过编译源代码、 运行待测试软件等步 骤, 在软件运行过程中根据设计的测试用例注入测试数据, 通过对软件的。
28、输出进行分析 (例 如, 与测试用例的预计输出进行对比) , 来观察软件运行是否正确, 检测软件是否存在错误。 软件测试技术的优点在于, 有一定的自动化功能, 可以进行测试用例管理、 批量测试和回归 测试。然而, 该技术的不足之处在于 : 1、 由于不直接面对源代码, 无法准确定位导致错误发 说 明 书 CN 103778061 A 6 2/19 页 7 生的源代码位置 ; 2、 由于错误定位不准确, 为软件的开发调试和校正造成了障碍。 0007 另一种有效的动态方法是将软件在一个虚拟机上运行, 该虚拟机可以模拟内存管 理模块, 从而检测软件中的数组越界错误。例如 JAVA 虚拟机就是一个典型。
29、的代表。虚拟机 技术的优点在于, 由于整个软件都处于被监控的状态, 因此检测结果非常准确。然而, 该技 术的不足之处在于 : 1、 由于虚拟机对软件的解释执行, 使得软件运行负载过大, 以至于软件 效率和性能降低非常明显 ; 2、 对于嵌入式安全关键工业控制系统, 由于高实时性和内存资 源受限的要求, 这样的效率和性能降低往往不能被接受, 因此这种方法并不实用。 0008 在检测到错误的存在后, 就需要对错误进行校正, 比如修改源代码。 对于校正数组 越界访问错误, 常用的方法是人工调试和校正。也就是说, 在软件测试阶段, 根据软件测试 工具的测试报告, 由程序员使用代码调试工具, 人工分析源。
30、代码的执行过程来定位错误。 这 一方法的优点是容易操作, 不需要使用额外的工具。然而, 该技术的不足之处在于 : 1、 当源 代码规模较大或者功能较为复杂, 程序员不一定能准确定位错误在源代码中的位置, 从而 无法正确地修改源代码 ; 2、 当软件已经被部署到目标平台上, 在实际运行过程中出现的数 组越界访问错误无法通过这种方法进行校正, 因此可能会引起软件失效、 系统故障或黑客 攻击。 0009 因此, 有必要提供一种新的数组越界错误的自动检测和校正方法, 以实现更准确 的错误定位功能, 更好的运行时效率和性能, 以及更自动化的运行时错误校正功能, 从而克 服现有的检测数组越界错误的方法中存。
31、在的技术问题。 发明内容 0010 为了克服上述已有技术存在的不足, 本发明的目的旨在提供一种新的检测和校正 数组越界错误的方法, 通过使用源代码变换技术, 将源代码变换为带有自动检测和校正功 能的源代码, 使得可以在软件运行过程中自动检测和校正软件中数组越界错误, 以实现更 准确的错误定位功能, 更好的运行时效率和性能, 以及更自动化的运行时错误校正功能, 从 而克服现有的检测数组越界错误的方法中存在的技术问题。 0011 本发明提供一种数组越界错误的自动检测和校正方法, 其特征在于, 包括 : 步骤 1、 选择待变换的源代码项目目录, 或者单个源代码文件 ; 步骤 2、 针对待变换的源代码。
32、, 利 用编译器生成源代码的符号表和抽象语法树 ; 步骤 3、 遍历抽象语法树中的所有结点, 构造 指针依赖图, 并进行源代码变换计算 ; 步骤 4、 根据步骤 3 的计算结果, 在源代码中将需替 换的部分源代码进行替换, 生成变换后的源代码, 并保存到新项目目录或新文件 ; 步骤 5、 定义数组越界检测策略和校正策略, 并将这些策略转化为函数定义, 将按照策略生成的函 数定义写入变换后源代码的开头部分 ; 步骤 6、 将变换后的项目目录或文件用原编译器进 行编译, 生成目标系统上的可执行文件 ; 步骤 7、 把生成的可执行文件部署到目标系统并运 行, 当可执行文件运行到那些替换或插入的代码段。
33、时, 将自动检测和校正数组越界错误, 并 准确报告错误对应的源代码位置。 0012 进一步地, 所述遍历抽象语法树中的所有结点, 构造指针依赖图, 并进行源代码变 换计算, 包括 : 指针依赖图是一个有向图二元组 (V,E), 其中 : V 是源代码中的指针集合并构 成指针依赖图中的结点集合, E 是源代码中的指针依赖关系集合并构成指针依赖图中的有 向边集合 ; 在遍历抽象语法树的过程中, 根据当前遍历到的结点 s 的类型进行如下操作之 说 明 书 CN 103778061 A 7 3/19 页 8 一 : 向指针依赖图中加入指针依赖关系, 将数组下标访问表达式和指针访问表达式替换为 函数调用。
34、, 将函数声明、 函数定义、 函数调用表达式替换为新的表达式。 0013 进一步地, 所述在遍历抽象语法树的过程中, 根据当前遍历到的结点 s 的类型进 行如下操作之一 : 向指针依赖图中加入指针依赖关系, 将数组下标访问表达式和指针访问 表达式替换为函数调用, 将函数声明、 函数定义、 函数调用表达式替换为新的表达式, 包括 : 在遍历抽象语法树的过程中, 对于当前遍历到的结点 s, 得到其所在的源文件名 filename 和代码行号 loc, 并根据结点 s 的类型分别进行如下操作 : 0014 操作 1、 如果结点 s 是一个带初始值的指针声明 type*p=expr, 其中 p 为指针。
35、名, expr 为表达式, 且 expr 中包含一个支配指针 q, 则将 (p,q) 作为一条边加入指针依赖图 ; 0015 操作 2、 如果结点 s 是一个指针赋值表达式 p=expr, 其中 p 为指针名, expr 为表达 式, 且 expr 中包含一个支配指针 q, 则将 (p,q) 作为一条边加入指针依赖图 ; 0016 操作 3、 如果结点 s 是一个数组下标表达式 pexpr, 其中 p 为指针名或数组名, expr 为表达式, 则根据 p 的类型分别进行如下操作 : 0017 操作 31、 如果 p 是符号表中已定义的一个数组, 则从符号表中获取该数组的类型 type 和长度 。
36、len, 然后将该表达式替换为如下函数调用 : 0018 *(type*)(_MNT_CHECK_AAV(p+expr,p,p+len,filename,loc) 0019 其中, 函数参数 p+expr 表示数组下标表达式访问的内存地址, 函数参数 p 表示数 组的起始地址, 函数参数p+len表示数组的结束地址, 函数参数filename表示源文件名, 函 数参数 loc 表示代码行号 ; 0020 操作32、 如果p是所在函数声明的第n个形式参数, 则从符号表中获取该指针的类 型 type, 然后将该表达式替换为如下函数调用 : 0021 *(type*)(_MNT_CHK_AAV(p+。
37、expr,_MNT_CHK_AAV_B_n,_MNT_CHK_AAV_E_ n,filename,loc) 0022 其中, 函数参数 p+expr 表示数组下标表达式访问的内存地址, 函数参数 _MNT_ CHK_AAV_B_n表示第n个形式参数的起始地址, 函数参数_MNT_CHK_AAV_E_n表示第n个形 式参数的结束地址, 函数参数 filename 表示源文件名, 函数参数 loc 表示代码行号 ; 0023 操作 33、 如果 p 是不满足以上操作 31、 操作 32 中的两种情况的指针, 则从指针依 赖图中获取其最终依赖指针 q, 如果 q 不存在, 则认为源代码中存在指针使用。
38、前未赋初值的 错误, 并报错, 如果 q 存在, 则根据 q 的类型分别进行如下操作 : 0024 操作 331、 如果 q 是符号表中已定义的一个数组, 则从符号表中获取指针 p 的类型 type 和数组 q 的长度 len, 然后将该表达式替换为如下函数调用 : 0025 *(type*)(_MNT_CHECK_AAV(p+expr,q,q+len,filename,loc) 0026 其中, 函数参数 p+expr 表示数组下标表达式访问的内存地址, 函数参数 q 表示数 组的起始地址, 函数参数q+len表示数组的结束地址, 函数参数filename表示源文件名, 函 数参数 loc 。
39、表示代码行号 ; 0027 操作 332、 如果 q 是所在函数声明的第 n 个形式参数, 则从符号表中获取指针 p 的 类型 type, 然后将该表达式替换为如下函数调用 : 0028 *(type*)(_MNT_CHK_AAV(p+expr,_MNT_CHK_AAV_B_n,_MNT_CHK_AAV_E_ n,filename,loc) 说 明 书 CN 103778061 A 8 4/19 页 9 0029 其中, 函数参数 p+expr 表示数组下标表达式访问的内存地址, 函数参数 _MNT_ CHK_AAV_B_n表示第n个形式参数的起始地址, 函数参数_MNT_CHK_AAV_E_。
40、n表示第n个形 式参数的结束地址, 函数参数 filename 表示源文件名, 函数参数 loc 表示代码行号 ; 0030 操作 333、 如果 q 是不满足以上操作 331、 操作 332 中的两种情况的指针, 则认为源 代码中存在指针使用前未赋初值的错误, 并报错 ; 0031 操作 4、 如果结点 s 是一个指针访问表达式 *expr, 其中 expr 为表达式, 且 expr 中 包含一个支配指针 p, 则根据 p 的类型分别进行如下操作 : 0032 操作 41、 如果 p 是符号表中已定义的一个数组, 则从符号表中获取该数组的类型 type 和长度 len, 然后将该表达式替换为。
41、如下函数调用 : 0033 *(type*)(_MNT_CHECK_AAV(expr,p,p+len,filename,loc) 0034 其中, 函数参数 expr 表示指针访问表达式访问的内存地址, 函数参数 p 表示数组 的起始地址, 函数参数p+len表示数组的结束地址, 函数参数filename表示源文件名, 函数 参数 loc 表示代码行号 ; 0035 操作42、 如果p是所在函数声明的第n个形式参数, 则从符号表中获取该指针的类 型 type, 然后将该表达式替换为如下函数调用 : 0036 *(type*)(_MNT_CHK_AAV(expr,_MNT_CHK_AAV_B_n。
42、,_MNT_CHK_AAV_E_ n,filename,loc) 0037 其中, 函数参数 expr 表示指针访问表达式访问的内存地址, 函数参数 _MNT_CHK_ AAV_B_n表示第n个形式参数的起始地址, 函数参数_MNT_CHK_AAV_E_n表示第n个形式参 数的结束地址, 函数参数 filename 表示源文件名, 函数参数 loc 表示代码行号 ; 0038 操作 43、 如果 p 是不满足以上操作 41、 操作 42 中的两种情况的指针, 则从指针依 赖图中获取其最终依赖指针 q, 如果 q 不存在, 则认为源代码中存在指针使用前未赋初值的 错误, 并报错, 如果 q 存在。
43、, 则根据 q 的类型分别进行如下操作 : 0039 操作 431、 如果 q 是符号表中已定义的一个数组, 则从符号表中获取指针 p 的类型 type 和数组 q 的长度 len, 然后将该表达式替换为如下函数调用 : 0040 *(type*)(_MNT_CHECK_AAV(expr,q,q+len,filename,loc) 0041 其中, 函数参数 expr 表示指针访问表达式访问的内存地址, 函数参数 q 表示数组 的起始地址, 函数参数q+len表示数组的结束地址, 函数参数filename表示源文件名, 函数 参数 loc 表示代码行号 ; 0042 操作 432、 如果 q 。
44、是所在函数声明的第 n 个形式参数, 则从符号表中获取指针 p 的 类型 type, 然后将该表达式替换为如下函数调用 : 0043 *(type*)(_MNT_CHK_AAV(expr,_MNT_CHK_AAV_B_n,_MNT_CHK_AAV_E_ n,filename,loc) 0044 其中, 函数参数 expr 表示指针访问表达式访问的内存地址, 函数参数 _MNT_CHK_ AAV_B_n表示第n个形式参数的起始地址, 函数参数_MNT_CHK_AAV_E_n表示第n个形式参 数的结束地址, 函数参数 filename 表示源文件名, 函数参数 loc 表示代码行号 ; 0045 。
45、操作 433、 如果 q 是不满足以上操作 431、 操作 432 中的两种情况的指针, 则认为源 代码中存在指针使用前未赋初值的错误, 并报错 ; 0046 操作 5、 如果结点 s 是一个函数声明或函数定义表达式 type func(,type_n 说 明 书 CN 103778061 A 9 5/19 页 10 expr_n,), 其中 : 第n个参数表达式expr_n为type_n类型的数组或指针声明p, 省略号 表示其它参数表达式, 则将该函数声明或函数定义替换为如下函数 : 0047 type func(,type_n expr_n,void*_MNT_CHK_AAV_B_n,vo。
46、id*_MNT_CHK_AAV_ E_n,) 0048 其中, 省略号表示原来的所有参数表达式, 函数参数 _MNT_CHK_AAV_B_n 表示 第 n 个参数表达式的起始地址, 函数参数 _MNT_CHK_AAV_E_n 表示第 n 个参数表达式的结 束地址 ; 0049 操作 6、 如果结点 s 是一个函数调用表达式 func(,expr_n,), 其中 : 第 n 个参 数表达式expr_n中包含一个支配指针p, 省略号表示其它参数表达式, 则根据p的类型分 别进行如下操作 : 0050 操作 61、 如果 p 是符号表中已定义的一个数组, 则从符号表中获取该数组的长度 len, 然后。
47、将该表达式替换为如下函数调用 : func(,expr_n,p,p+len,), 其中, 省略号 表示原来的所有参数表达式, 函数参数p表示数组的起始地址, 函数参数p+len表示数组的 结束地址 ; 0051 操作62、 如果p是所在函数声明的第n个形式参数, 则将该表达式替换为如下函数 调用 : 0052 func(,expr_n,_MNT_CHK_AAV_B_n,_MNT_CHK_AAV_E_n,) 0053 其中, 省略号表示原来的所有参数表达式, 函数参数 _MNT_CHK_AAV_B_n 表示 第 n 个形式参数的起始地址, 函数参数 _MNT_CHK_AAV_E_n 表示第 n 。
48、个形式参数的结束地 址 ; 0054 操作 63、 如果 p 是不满足以上操作 61、 操作 62 中的两种情况的指针, 则从指针依 赖图中获取其最终依赖指针 q, 如果 q 不存在, 则认为源代码中存在指针使用前未赋初值的 错误, 并报错, 如果 q 存在, 则根据 q 的类型分别进行如下操作 : 0055 操作 631、 如果 q 是符号表中已定义的一个数组, 则从符号表中获取数组 q 的长度 len, 然后将该表达式替换为如下函数调用 : func(,expr_n,q,q+len,), 其中, 省略号 表示原来的所有参数表达式, 函数参数q表示数组的起始地址, 函数参数q+len表示数组。
49、的 结束地址 ; 0056 操作 632、 如果 q 是所在函数声明的第 n 个形式参数, 则将该表达式替换为如下函 数调用 : 0057 func(,expr_n,_MNT_CHK_AAV_B_n,_MNT_CHK_AAV_E_n,) 0058 其中, 省略号表示原来的所有参数表达式, 函数参数 _MNT_CHK_AAV_B_n 表示 第 n 个形式参数的起始地址, 函数参数 _MNT_CHK_AAV_E_n 表示第 n 个形式参数的结束地 址 ; 0059 操作 633、 如果 q 是不满足以上操作 631、 操作 632 中的两种情况的指针, 则认为源 代码中存在指针使用前未赋初值的错误, 并报错。 0。