Functional Code Clone Detection with Syntax and Semantics Fusion Learning论文总结

一、任务简介

         代码克隆就是指源码中两段代码非常相似的现象。代码克隆检测有四个层次:

        1. 代码语句完全相同;

        2. 在1的基础上改变一些变量名、类型名或者是函数名;

        3. 在2的基础上增加或者减少一些语句;

        4. 功能相似,代码语句有很大差别。

        一般有四种类型检测方法,基于文本和基于记号的方法一般用于对1.2类型的检测,基于语法的方法一般可以用于对1.2.3类型的检测以及部分4类型的检测。基于语义的方法则可以考虑到代码的功能。

        本文是检测第四种类型的代码克隆,即Functional Code Clone detection:功能层面代码克隆的检测。采用了语法和语义结合的方式。

二、方法流程简介

        1. 从源码中分析出方法之间的调用图、每个方法的抽象语法树以及每个方法的控制流图;

        2. 用调用图将找出每个功能的AST集合。通过AST集合抽取功能的语法信息;

        3. 通过调用图组成每个功能的控制流图。通过控制流图抽取功能的语义信息;

        4. 将抽取出来的语义信息送入前馈神经网络得到分类结果

        5. 这样设计流程的原因:

        首先是调用图,作者用调用图的目的主要是考虑到功能性的代码克隆不只是与单个方法有关,调用图将有调用关系的方法连成一个整体,表示一个完整的功能。作者给了一个例子:

        

        其次作者选用了抽象语法树和控制流图,他们分别代表程序两方面的特征,一个是语义,一个是语法,他俩是相辅相成的。比如有一个功能既可以用递归调用实现又可以用一个循环实现,这两个功能在语法上差别是很大的,但是他们的控制流图里面都包含了一个环结构。在比如这个例子:sample1和sample2的功能明显不同,但是他们的控制流图长得一模一样。这个时候就得靠抽象语法树来分辨。 

         

         作者还提到了一个比较的例子:程序依赖图。作者认为程序依赖图既包含语法信息又包含语义信息,但是对于语法信息来说它太过于粗糙,对于语义信息来说他又过于复杂,且需要较大的时间开销,所以用抽象语法树和比较简单的控制流图来分别抽取语法信息和语义信息。

        前馈神经网络。这个主要是因为语义信息和语法信息的共同差异无法用距离来进行衡量,也找不到一个合适的阈值,考虑到其复杂性以及比较差的可解释性,作责采用了深度神经网络将其转化为2分类问题。

三、方法流程细节

1. 调用图

        作者说本文是第一篇用调用图来进行分析的论文。特点就是将分析的层面从单个方法的层面提升到了功能的层面(前面我们说功能是有调用关系的一组方法)。

        所谓调用图就是反映函数之间关系的一种结构,论文里面是用<调用方法标识符,调用语句标识符,被调用方法标识符>三元组表示的(每个方法和语句都有一个全局唯一的标识符)。作者举出了六种常见的调用结构:

        

        第一种就是没有任何调用关系。他的抽象语法树和控制流图都是该该函数的语法树和控制流图。

        第二种就是递归调用自身,它的抽象语法树也没有任何改变,但是控制流图会增加一条从递归调用语句到方法入口的有向边。

        3.4.5是类似的,调用函数和被调用函数形成一个功能,他们的抽象语法树组成一个语法树集合,控制流图则通过有向边的连接来组成一个整体。

         

        第六种则要看成两个功能。

2. 抽象语法树以及语义信息获取。编译原理里面的一个概念,树的每一个节点都是程序的一个记号,如下图。

        这里作者将每个方法的抽象语法树进行先序遍历形成一个序列。然后根据调用图把被调用的方法的抽象语法树先序序列都加入形成一个集合。 

        这里有一个细节,程序里面变量和常量的表示,用的是变量的类型加上一个全局范围内自增的数字,比如int1,其次是小数一律看作double,不区分double和float。这个细节还是非常重要的。剩下的关键字则都用全局标识符来表示。

        接下来是语法特征的表示。作者用的是word2vec形成每个节点的语法向量,然后把每个方法里面的语法向量做个平均池化,获得每个方法的语法向量。最后给功能中每个方法的语法向量做个平均池化,得到功能的语法向量表示。这样就得到了功能的语法信息。

        当然作者也用了其他图嵌入算法作比较,后面再说。

3. 控制流图以及语义信息。

        首先按照前面调用图所说的六种调用模式得到功能的控制流图。然后作者选用了graph2Vec的图嵌入算法,将图的每个节点映射到低维向量空间,每个向量都会包含整个图的信息。没有提到其他细节。

        同样,作者也使用了其他图嵌入算法进行比较。

4. 前馈神经网络。

        前面说过语义信息和语法信息无法用距离来衡量相似性,如下图:

        阈值很难找,即使是将语义和语法分开考虑,由于他俩很有可能得出完全相反的结论,也很难进行判别。这个问题比较抽象和复杂,因此采用了神经网络的方法。 

        

        上图是神经网络的结构,是几个全连接层拼接而成,v1和v2是俩功能的表示向量。考虑到他俩的顺序可能影响结果,作者把正序和逆序输入拼接在一起作为网络的输入。

 5. 实验设定

         代码语言:c/c++

        数据集:OJClone,包含104种任务,每种任务包含500个不同学生提交的源码。每一个任务种的源码可以被认为是实现了同一种功能。作者选了35个任务,每个任务选择了100份源码。由于输入是代码对,显然当任务数量多于2的时候就会出现严重的数据集不平衡现象,这里就是负样本远远多于正样本。所以采用了下采样的方法减少负样本数量。下采样的细节没有提到。最后暗8:2随机分成训练集和测试集。

6. 实验结果

        

        这张图还是挺能说明问题的。Deckard和DLC都是精确率比召回率高出一截,说明他们的分类方法过于严格了。作者分析,Deckard是将代码映射成了一个特征向量,然后用欧式距离来衡量相似度,作者认为特征的每一个维度所占的权重应当不一样,采用欧氏距离会使每个维度的重要程度相同,因此只有在两段代码相似度非常高时才会判定两者是克隆代码。DLC的情况是类似的。SourcererCC和CDLH与上面相反,他们的分类方式过于宽松。可以说本文的方式与上述相比最为折中,所以取得了最好的效果。

        时间性能比较,没有太多需要注意的地方。 

四、有效性验证

1. 融合代码表示

        作者采用了语法和语义两种方法来表示代码,为了验证这种方法的有效性,作者设计实验给七种情况下的表示方法进行了比较,如下图 

        

        Text表示方法就是完全将代码作为一种自然语言,进行相应的词嵌入学习。结果可以看出语法和语义表示的加入可以取得更好的结果。 

2. Word2vec和Graph2vec

        同样设计了实验进行验证:

        

        作者认为与其他图嵌入方式相比,graph2vec可以表示图的整体结构特征,而其他方式只是表示了各个节点的结构后取平均值,无法反映整体情况。

        作者说glove加入了一些表示整体特征的因素,但在实际应用中word2vec效果更好,作者没有给出明确的理由,但是我个人推断是因为语法树的先序遍历序列还是与自然语言有很大的出入,可能其先序遍历序列不能从整体上反映语法树的情况,因此起到了负面的效果。

         

3. 特征向量长度验证

        一个调参实验,向量过短会导致信息不足,不能很好的表达语法和语义信息。过长则会导致资源浪费。经过实验,作者确定了长度为16最佳。 

4. 神经网络的有效性验证

        

        比较了传统机器学习算法svm和逻辑回归与深度神经网络的效果,结果是神经网络效果较好。

五、不足

        该方法是基于函数间的调用的,无法检测没有调用关系的代码。

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值