基于后缀树的代码文件克隆检测方法与流程

文档序号:11653979阅读:322来源:国知局
基于后缀树的代码文件克隆检测方法与流程

本发明涉及一种检测方法,尤其涉及一种基于后缀树的代码文件克隆检测方法。



背景技术:

从软件产业的诞生到现在,随着计算机用户数量快速增加,软件产业发展迅猛,已渗透到人们工作与生活的方方面面。许多软件源代码开放在互联网上,开发人员在互联网查询所需要的相关代码已成为一种快速有效的生产方式。由于共同的软件功能,经过简单修改或者直接的复制粘贴,代码重用已经是软件开发中一个通用行为。开源代码的快速发展,上百万的软件工程源代码在相关网络上可以查找,如googlecodesearch,github,snippir,sourceforge,github等,今天开源代码已经在软件发展中处于重要地位。随之而来的现象就是,无论有意或无意的复制开源代码,软件系统存在代码段与其他代码非常相似,也称之为代码克隆。在一般的软件系统中都存在明显代码克隆部分,代码相似比例在7%-23%。

代码克隆通常是有目的性的,可以减轻开发人员重复性工作,专注核心功能研发等,从这些方面来说是有用的。但是也存在许多问题不利于软件的维护和扩展。例如,在一个代码段中存在漏洞,所有相似的代码段都应该被检测出相同漏洞。特别是直接使用开源代码,没有任何风险意识的人员也将开源代码的问题带入开发的软件系统。这些产品应用在国防、医疗、金融等重要领域,给工作带来巨大的潜在风险。

在大型软件系统中,代码的雷同、抄袭现象频发,人们维权意识增强,一些代码克隆侵犯了其他软件公司的知识产权。为保护软件产权,软件公司提前做好软件技术秘密的认定、保密措施,申请专利权、软件著作权登记。但是在发生侵权行为后,需要对软件产品进行判定,以维护自己的权利,这对两方公司都产生严重影响。

无意识的代码克隆使软件产品引入外部风险,可以依赖代码克隆检测,在软件开发过程中得到避免或警示。一方面根据开源代码公布的漏洞,代码克隆检测出所有漏洞,可以让开发人员认识存在的问题,对风险进行识别再决定是否使用开源代码。另一方面,也能了解软件系统使用非自主开发代码情况,评估该软件产品的技术含量。

还存在许多其他的软件工程任务需要代码克隆检测,如程序理解,了解克隆代码领域知识;代码质量分析,较少的克隆可能意味着更好的代码质量;对软件进行演化分析;分析代码重复程度,对代码进行压缩;根据代码来源进行代码病毒检测以及代码错误检测。而软件开发基于计算机语言,语言结构简单,比自然语言更易被机器识别。软件工程任务需要能够自主进行代码克隆检测的工具,识别克隆代码的漏洞、知识产权、授权许可等信息。并且与一般文本的自然语言克隆检测不同,根据不同类型的代码克隆,代码克隆有一定规律性,也更适合自动检测。

现在代码克隆检测研究都是基于两个代码段间进行比对,实际无法提前知道该软件复制哪些代码源,需要将代码与大量代码进行匹配检测,对于检测效率有更高的要求。而使用开源代码是直接导入整个开源项目,若进行代码内容匹配则花费更多时间。本专利在代码克隆检测对象上,由一对一向一对多进行,分析不同克隆情况并开发检测工具,进行实际应用。

有鉴于上述的缺陷,本设计人,积极加以研究创新,以期创设一种基于后缀树的代码文件克隆检测方法,使其更具有产业上的利用价值。



技术实现要素:

为解决上述技术问题,本发明的目的是提供一种基于后缀树的代码文件克隆检测方法。

本发明的基于后缀树的代码文件克隆检测方法,其中:对工程项目文件构造后缀树,在线性时间内实现代码文件克隆检测,其包括以下步骤:

步骤一,构造开源项目指纹库,采用的后缀树为ukkonen算法,

步骤二,对代码文件克隆进行检测,

若从指纹库中直接检索相同的文件指纹,整个检测实现的算法复杂度为o(mn),m为待检测项目的文件指纹数,n是指纹库的指纹数;

以后缀树方法为基础,完成在线性时间内检测相同代码文件。

进一步地,上述的基于后缀树的代码文件克隆检测方法,其中,所述步骤一中,

代码文件为粒度构造代码指纹,所述代码指纹直接保存在主服务器上,建立指纹库和代码克隆检测;

用户输入相关信息并上传开源工程项目,或是选择直接从网络上进行自动抓取,对开源工程项目解压并存放到指定目录,遍历开源项目,对符合用户输入语言的代码文件进行处理;

根据用户输入的最小文件行数对较少行数的代码文件进行过滤,通过md5哈希得到指纹值,并将指纹保存到mysql数据库中。

更进一步地,上述的基于后缀树的代码文件克隆检测方法,其中,所述步骤一中,以代码文件自定义对象的序列作为节点内容,自定义对象filenode结构如表所示,

文件粒度指纹库保存在mysql数据库的t_file_hash表中,

更进一步地,上述的基于后缀树的代码文件克隆检测方法,其中,所述步骤一中,将开源工程项目添加到指纹库中,遍历该工程项目,对符合条件的代码文件采用jflex进行词法分析过滤,并md5哈希。

更进一步地,上述的基于后缀树的代码文件克隆检测方法,其中,采用的算法括构建后缀树和递归处理剩余后缀节点两部分,构造后缀树的伪代码表,

对两个工程项目构成的filenode序列构造后缀树,遍历序列每个对象,如果后缀树中存在当前对象指纹值为前缀的后缀,则改变三元组和剩余后缀数的值,否则直接添加到当前节点的子节点;

对于已经保存的待插入剩余后缀,直到遍历到不存在以当前对象为前缀的后缀节点,则需要对后缀树进行分裂;

分裂活动中,将活动节点的filenode序列以活动长度作为分裂点,前半部分作为活动节点的序列,后半部分添加到其子节点,并且将当前剩余序列添加到活动节点的子节点;

分裂完成后按照三个规则处理三元组,最后按照剩余插入后缀数递归处理待插入的filenode序列。

更进一步地,上述的基于后缀树的代码文件克隆检测方法,其中,所述步骤一中,对ukkonen算法进行适应性优化,将后缀树构造应用到代码文件克隆检测中,包括,

d)序列节点,每次插入新对象时,构造的新节点内容为对象序列,而不是单个对象;

e)节点标记,在构造后缀树过程中及时标记公共子串所在的节点;

减少比较,扫描一个新文件对象时,查找是否存在以该文件相同指纹值的对象为开头的后缀节点时,对标记为不可能是克隆文件的节点不进行比较。

更进一步地,上述的基于后缀树的代码文件克隆检测方法,其中,每次插入新节点时,节点内容是以该字符为起始位置到结束的序列,

检测两个filenode序列的克隆代码文件,在两个项目序列中间添加标识符标识一个项目的结束,而在构造过程中,若一个非叶节点的子节点中含有这个标识符,则说明这个非叶节点的filenode对象既在检测任务中出现也在开源项目中出现,为两个项目的克隆代码文件。

再进一步地,上述的基于后缀树的代码文件克隆检测方法,其中,所述步骤二中,进行克隆度和相似度计算,

根据后缀树构造过程中保存的克隆结果进行统计计算,检测项目的克隆度指该项目有克隆开源项目的代码文件行数占所有代码文件行数和的比值,定义如公式1所示,fi是检测项目克隆文件,fj是检测项目代码文件,line表示该文件的行数,

相似度,指检测项目与一个开源项目的相似度,检测项目与开源项目克隆的文件行数占两个项目所有代码文件行数和的比值,定义如公式2所示,fi是检测项目克隆文件,pi是开源项目克隆文件,fj是检测项目代码文件,pj是开源项目代码文件,line表示该文件的行数,

借由上述方案,本发明能在线性时间内检测出克隆的代码文件,比直接按照指纹值进行检测有更高效率,实现海量检测。

上述说明仅是本发明技术方案的概述,为了能够更清楚了解本发明的技术手段,并可依照说明书的内容予以实施,以下以本发明的较佳实施例并配合附图详细说明如后。

附图说明

图1是构建文件粒度指纹库流程图。

图2是代码克隆来源分析系统流程图。

具体实施方式

下面结合附图和实施例,对本发明的具体实施方式作进一步详细描述。以下实施例用于说明本发明,但不用来限制本发明的范围。

如图1、图2的基于后缀树的代码文件克隆检测方法,其是对工程项目文件指纹构造后缀树,在线性时间内实现代码文件克隆检测,采用如下步骤:

步骤一,构造开源项目指纹库。

以代码文件为粒度构造代码指纹,指纹数量可控,占用存储空间有限,因此可以直接保存在主服务器上。实现本发明的后台主要完成两个功能,建立指纹库和代码克隆检测。具体来说,用户输入相关信息并上传开源工程项目或者选择直接从网络上进行自动抓取,对开源工程项目解压并存放到指定目录,遍历开源项目,对符合用户输入语言的代码文件进行处理。同时,可以根据用户输入的最小文件行数对较少行数的代码文件进行过滤,不少于设置行数的代码文件进行词法分析过滤,并md5哈希得到指纹值,并将指纹保存到mysql数据库中。

本发明所设计的文件粒度指纹库保存在mysql数据库的t_file_hash表中,表的具体信息如表1所示。因为文件粒度指纹是以一个文件为对象,所有指纹存储数据简单,最核心字段代码文件指纹值hash。为了确定是哪个开源工程项目工程文件则需要保存路径location。开源工程项目id的设计是由于克隆检测时,后缀树检测以两个工程项目的指纹序列为基础,需要按工程项目检索指纹值。为此,在该表中不需要为指纹值hash建立数据库索引,而是为了能够快速按照工程项目进行检索,在创建表时候对字段projectid建立索引。

表1t_file_hash表。

在此期间,将开源工程项目添加到指纹库中,遍历该工程项目,对符合条件的代码文件采用jflex进行词法分析过滤,并md5哈希。应用本发明的系统使用的md5算法是使用java.security.messagedigest定义的算法。这是一个单向散列函数,任意长度的字符序列生成固定长度的证书。为了方便处理和提高比较效率,将md5获得的128位长整数,对处理得到32位的十六进制哈希值。

步骤二,代码文件克隆检测如果使用从指纹库中直接检索相同的文件指纹,整个检测实现的算法复杂度为o(mn)。其中,m为待检测项目的文件指纹数,n是指纹库的指纹数。在实际实施期间,为了实现相同的目标,并且提高算法效率,lp代码文件克隆检测算法以后缀树方法为基础,能够完成在线性时间内检测相同代码文件。

结合本发明一较佳的实施方式来看,本发明在实施期间所提出的检测算法基础是后缀树ukkonen算法,其以代码文件自定义对象的序列作为节点内容,自定义对象filenode结构如表1所示。

具体来说,采用filenode表示一个代码文件的指纹对象,即工程项目文件的hash值。filenode序列相当于字符串序列,filenode的指纹值相当于字符的值,通过构造filenode序列的后缀树将文件检测转换为文件对象的“字符串”检测。为了有效检测两个字符串的公共子串,在两个字符串的中间添加一个唯一的不会在字符串中出现的字符作为标识,后缀树节点中根据这个标识来判断某个非叶节点是否是公共子串。

同时,在filenode序列后缀树的构造过程中,以比较指纹值相等与否来确定两个filenode对象是否存在克隆关系,并在待检测工程项目序列结尾添加一个hash值为#的filenode对象为标识。

由于开源工程项目代码文件数量较多,不可能一次性构造用户项目和所有开源项目构成的filenode序列后缀树,并且开源工程项目之间也存在代码克隆关系,一次性构造也可能产生许多不必要结果。所以,将待检测工程项目和一个开源工程项目得到的filenode序列构造后缀树,得到其“公共子串”也就是克隆的代码文件,实现代码文件的克隆检测。遍历所有开源工程项目,就完成了检测。

例如:用户检测任务有4个文件n(i),开源工程项目有3个文件m(i),加上项目标识符#和结束标识符$构成9个filenode对象的序列,对该序列构造后缀树也在图中显示。序列后缀树中除了根节点,存在两个非叶节点,并且这两个非叶节点都存在含有#标识符的叶子节点,说明这两个节点是公共子串,也就是两个工程项目的克隆代码文件。

n(i)表示待检测工程项目文件的filenode,m(i)表示开源工程项目文件filenode,f表示filenode序列,该序列:n(1)n(2)…n(n)#m(1)m(2)…m(m)$。以f为输入构造后缀树,后缀树的每个叶子节点是以$为结尾的f子序列,每个非叶节点是f的子序列且有三种形式:n(i)…n(j)、n(i)…n(n)#m(1)…m(j)和m(i)…m(j)。如果n(i)和m(j)是克隆文件,则在f构造的后缀树中存在某个非叶节点,且该节点的子序列中存在n(i)文件的filenode。

结合算法中核心变量三元组(活动节点,活动边,活动长度)来看,其中中,节点是后缀树的节点,剩余后缀数指已经遍历过待插入的filenode数。判断某个filenode是否已经在后缀树中存在以该文件为开头的后缀,是根据三元组直接进行判断,以filenode的hash值是否相等判断filenode相等与否。

以本发明实施期间的算法实现来看,主要包括构建后缀树和递归处理剩余后缀节点两部分,构造后缀树的伪代码如表2所示。

对两个工程项目构成的filenode序列构造后缀树,遍历序列每个对象,如果后缀树中存在当前对象指纹值为前缀的后缀,则改变三元组和剩余后缀数的值,否则直接添加到当前节点的子节点。对于已经保存的待插入剩余后缀,直到遍历到不存在以当前对象为前缀的后缀节点,则需要对后缀树进行分裂。分裂活动边,将活动节点的filenode序列以活动长度作为分裂点,前半部分作为活动节点的序列,后半部分添加到其子节点,并且将当前剩余序列添加到活动节点的子节点。分裂完成后按照三个规则处理三元组,最后按照剩余插入后缀数递归处理待插入的filenode序列。

表2lp代码文件克隆检测后缀树构造算法伪代码。

根据剩余后缀数插入之前未插入的filenode,递归调用处理函数innersplit,直到filenode都被处理,分裂递归处理算法innersplit的伪代码如表3所示。与构造后缀树的算法处理流程相同,只需要把当前处理节点由当前输入的filenode变成当前剩余插入的filenode,按照规则更改三元组变量,递归调用直到剩余后缀数变量rest为0。

表3分裂递归处理算法伪代码。

本发明在实施期间,还对ukkonen算法进行了适应性优化。

将后缀树构造应用到代码文件克隆检测中,为了提高算法效率,主要做了三点优化:

f)序列节点。每次插入新对象时,构造的新节点内容为对象序列,而不是单个对象。

g)节点标记。在构造后缀树过程中及时标记公共子串所在的节点。

h)减少比较。扫描一个新文件对象时,查找是否存在以该文件相同指纹值的对象为开头的后缀节点时,对标记为不可能是克隆文件的节点不进行比较。

具体来说:

第一个优化,在ukkonen算法中,每次插入新的字符时,若后缀树中不存在该字符的后缀,则插入新节点,节点内容是该字符。在代码文件克隆检测后缀树算法中,每次插入新节点时,节点内容是以该字符为起始位置到结束的序列。ukkonen算法是不需要事先知道输入字符串所有内容,使用增量方式构造后缀树,构造过程中采用压缩方式存储了后缀树。

但是,在代码文件克隆检测中,要构造后缀树时已经事先知道完整的filenode序列。为此,每次插入新节点时可以考虑不要修改已有的后缀树节点。由此算法设计在后缀树构造时,每次插入新节点时以当前节点为开始的剩余的filenode序列。

特别是在代码工程项目中,一个项目里存在相同的代码文件情况较少,克隆检测构造的后缀树大多数情况下只有三层,除了克隆的代码文件外其他都是叶子节点。若直接使用ukkonen算法,对叶子节点的扩展会成为一个较大的开销,算法做了这样的优化后则会减少扩展的操作避免开销。

第二个优化,首先后缀树解决字符串问题,非叶节点表示字符串中重复的子串。检测两个filenode序列的克隆代码文件,也就是检测出构造这个两个序列合并序列的后缀树中的部分非叶节点。之所以说是部分非叶节点,因为存在一个代码项目中有两个相同文件的情况,这些文件构成的节点也是非叶节点。为了保证结果的准确性,在两个项目序列中间添加标识符标识一个项目的结束,而在构造过程中,若一个非叶节点的子节点中含有这个标识符,则说明这个非叶节点的filenode对象既在检测任务中出现也在开源项目中出现,也就是两个项目的克隆代码文件。

第三个优化,在按顺序扫描一个新文件对象时,要在后缀树中查找是否存在以该文件相同指纹值的对象为开头的节点。在ukkonen算法中,需要对活动节点对应的子节点全部遍历以查找。在本算法的实际应用情况中,对于被标记为不可能是克隆文件的节点可以不进行比较,因为从#之后的filenode是待检测项目自己的文件,肯定不是克隆文件,所以对这些节点都可以忽略,可有效提高算法效率。

步骤三,进行克隆度和相似度计算。

根据后缀树构造过程中保存的克隆结果进行统计计算。检测项目的克隆度指该项目有克隆开源项目的代码文件行数占所有代码文件行数和的比值。定义如公式1所示,fi是检测项目克隆文件,fj是检测项目代码文件,line表示该文件的行数。

相似度指检测项目与一个开源项目的相似度,检测项目与开源项目克隆的文件行数占两个项目所有代码文件行数和的比值。定义如公式2所示,fi是检测项目克隆文件,pi是开源项目克隆文件,fj是检测项目代码文件,pj是开源项目代码文件,line表示该文件的行数。

通过上述的文字表述并结合附图可以看出,采用本发明后,检测实现能在线性时间内检测出克隆的代码文件,比直接按照指纹值进行检测有更高效率,实现海量检测。

以上所述仅是本发明的优选实施方式,并不用于限制本发明,应当指出,对于本技术领域的普通技术人员来说,在不脱离本发明技术原理的前提下,还可以做出若干改进和变型,这些改进和变型也应视为本发明的保护范围。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1