Page 108 - 《软件学报》2020年第11期
P. 108
3424 Journal of Software 软件学报 Vol.31, No.11, November 2020
对于常见的函数,均可以采用上述形式进行表示.根据函数功能的不同,可以分为如下几类.
(1) retval=strstr(arg1,arg2,…)类函数:这类函数实质上是对返回值 retval 进行定义,而对 retval 的定义又引
用了函数参数 arg1,arg2,….由于返回值 retval 可能会在后续的数据流中用到,因此可以表示为(strstr,
〈[retval],[arg1,arg2,…]〉),其中,[retval]为定义参数的集合,[arg1,arg2,…]为引用参数的集合.
(2) memcpy(arg1,arg2,arg3,…)类函数:这类函数实质上是对某个参数如 arg1 进行定义,而对该参数的定
义又引用了其他参数如 arg2,arg3,…;同时,这类函数没有返回值或返回值不会体现在后续的数据流
中,因此可以表示为(memcpy,〈[arg1],[arg2,arg3,…]〉),其中,[arg1]为定义参数的集合,[arg2,arg3,…]为
引用参数的集合.
(3) retval=strcpy(arg1,arg2,…)类函数:这类函数实质上是对某个参数如 arg1 进行定义,而对该参数的定
义又引用了其他参数如 arg2,…;同时,也对返回值 retval 进行了定义,而且返回值可能会体现在后续的
数据流中,因此可以表示为(strcpy,〈[arg1,retval],[arg2,…]〉),其中,[arg1,retval]为定义参数的集合,
[arg2,…]为引用参数的集合.
(4) system(arg1,…)类函数:这类函数只是引用函数参数如 arg1,…;同时,该函数没有返回值或返回值不会
体现在后续的数据流中,因此可以表示为(system,〈[⋅],[arg1,…]〉),其中,[⋅]为定义参数的集合,[arg1,…]
为引用参数的集合.
除了程序中的函数外,也可以将程序中的某些语句片段(或某条语句)抽象成函数,进而表示为 FDDG 中的
节点,最典型的就是实现循环拷贝的语句片段.循环拷贝是指在某个循环体内向不断改变的地址中写入数据,文
献[18]给出了识别循环拷贝代码片段的方法.本文方法将循环拷贝代码片段直接抽象成函数,并将存在循环依
赖关系的变量作为函数的参数,同时记录参数之间的“定义-引用”关系.在图 3 中,将实现循环拷贝的代码片段抽
象成 loop_copy 函数,同时保存循环间隔和循环终止条件等信息.这种处理方法拓展了函数级数据依赖图的表达
能力.
Fig.3 Example of abstracting a code snippet into a function
图 3 代码片段抽象为函数示例
2.2.2 函数级数据依赖图中的边
函数级数据依赖图中的边表示函数之间参数的依赖关系,主要包括“引用”和“消灭”两种关系.若 a 和 b 分别
为程序 P 中的两个函数,v 为两个函数共同的参数,这里将函数的返回值也看作函数的参数,当 a 和 b 满足以下
条件时,称函数 b 和函数 a 之间关于参数 v 存在“引用”关系.
(1) 函数 a 对参数 v 进行定义.
(2) 函数 b 引用参数 v.
(3) 函数 a 到函数 b 之间存在一条可执行路径,且此路径上不存在其他对参数 v 的定义.
类似地,当 a 和 b 满足下列条件时,称函数 b 和函数 a 之间关于参数 v 存在“消灭”关系.
(1) 函数 a 对参数 v 进行定义.
(2) 函数 b 对参数 v 进行重新定义.