一、前言
代码克隆(Code clone),是指存在于代码库中两个及两个以上相同或者相似的源代码片段,是软件开发中的常见现象。代码克隆能够提高效率,但也可能意外引入外部漏洞。下文是对代码克隆检测技术的简单整理。
二、克隆的类型
代码克隆的类型主要分为两大类,句法克隆(syntactic clones)和语义克隆(semantic clones)。句法克隆指文本相似的代码片段, 语义克隆则是指功能相似的代码片段。基于这两大类,代码克隆可以被划分为四小类,其中前三种为句法克隆,第四种为语义克隆。

当前,学术界对Type1,2,3类克隆的检测已颇为成熟,尤其是对Java和C++语言的克隆检测;而对Type4类克隆的检测准确率仍不高,无法达到工业界应用标准。
四类的代码示例可参照下图——
其中s1,s2,s3,s4 分别对照Type-1,2,3,4类的代码形式,加粗部分为修改部分。

三、克隆检测的通用流程
通览代码克隆检测领域的相关论文,可以发现代码克隆检测通常分三步走。

将源码拆分为对比单元(comparison units, 如class,function,block,statement)
将对比单元转化为中间表达(IR, Intermediate Representation,如token,AST, PDG)
再对这些对比单元的IR进行match detection(对比),通常是将对比单元组成clone pair的形式:一次对比两个(c1, c2)或是多个(c1, c2, c3)
四、克隆检测算法的分类
代码克隆检测发展至今,主要分为五大类检测思想: Textual, Token, Syntactic, Semantic, Learning。其具体分类见下图。

Textual:代码片段以文本/字符串/词法的形式相互比较,并且只有在两个代码片段在文本内容方面确实相同时才被发现被克隆。
Token:在编译器的词法分析阶段,所有源代码行都被划分为一系列Token。 然后将所有Token转换回Token序列。
Syntactic(句法分析): 基于树: 提取的AST用于子树比较以识别相似区域。 基于度量:通过源代码收集度量,然后使用这些度量为每个代码片段生成向量。然后使用向量对代码的相似度进行对比。
Semantic:主要检测代码片段不同,但功能相同的函数(Type4)
Learning : 通过机器学习和统计分析的方式来进行克隆检测
这几类对应的具体算法见下——
4.1 Textual
图中的oss指open source software

4.2 Token

4.3 Syntactic
4.3.1 Tree

4.3.2 Metric

4.4 Semantic
4.4.1 PDG

4.4.2 Other

4.5 Learning
4.5.1 ML

4.5.2 Other Learning

五、克隆检测的历史趋势
有关代码克隆检测的最早和最开创性的工作是在1990年代初期完成的,如下表所示。可以看出除了近年兴起的ML方法以外,代码克隆检测的开创性工作均在90年代和00年代就已完成,这也是笔者说该领域已颇为成熟的原因。
| 名称 | 算法思想 | 检测级别 |
|---|---|---|
| Baker,1992 | line-by-line comparison | Type-1,2 |
| Dup,1995 | parameterization | Type-1,2 |
| CloneDR,1998 | AST | Type-1,2 |
| CCFinder,2002 | token stream, a prefix tree and a novel matching algorithm, | Type-1,2 支持在分钟内实现百万行代码的检测。支持代码类型:C,C++,Java,COBOL |
| CP-Miner,2004 | 类CCFinder | bug-detection |
| Deckard, 2007 | tree-based | 在大型数据集上有很好的表现,如linux Kernel。可以检测 Type-1,2,3类的代码克隆 |
六、Benchmarks 基准
除工具本身之外,代码克隆检测工具的基准测试和有效性测试领域也有许多发展。其中比较有名的基准数据集是Bellon’s benchmark(2007)和 BigCloneBench(2015)。
| 基准 | 发布时间 | 描述 |
|---|---|---|
| Bellon’s benchmark | 2007 | 在两个小型C程序和两个小型Java程序上运行六个不同的代码克隆工具,并收集克隆结果。 将这些结果与真实代码克隆的主体进行比较,创建出代码克隆数据集。 |
| BigCloneBench | 2015 | BigCloneBench是IJaDataset-2.0(一个包含25,000个开源Java系统的大数据软件存储库)中800万个经过验证的克隆代码段。包含项目内和项目间的全部四种主要克隆类型。 |
七、开源工具
笔者整理了部分已开源的学术成果,地址见下。
八、References
[1] Walker A, Cerny T, Song E. Open-source tools and benchmarks for code-clone detection: past, present, and future trends[J]. ACM SIGAPP Applied Computing Review, 2020, 19(4): 28-39.
[2] Roy C K, Cordy J R, Koschke R. Comparison and evaluation of code clone detection techniques and tools: A qualitative approach[J]. Science of computer programming, 2009, 74(7): 470-495.

广东省广州市 1F
之前搞过克隆检测,AST那套在C++里折腾了好久才跑通
广东省佛山市顺德区 B1
@ 花间醉客 C++那破语法树,模板一嵌套就炸,谁搞谁知道
浙江省衢州市 B1
@ 花间醉客 C++的AST环境配起来太折磨,尤其模板那一块,头大
浙江省杭州市 2F
求问CloneWorks能处理Python吗?看支持语言没写清楚
福建省福州市 B1
@ 墨砚凝霜 CloneWorks官方文档里没写Python,我也试过,报错说解析器不支持,估计只能手动改源码了 😂
福建省厦门市 3F
又是学术向整理,工业界真用得上吗?🤔
北京市 B1
@ 山月不知 工业界用啊,我们组就拿来做代码审计,省不少功夫。
上海市 4F
感觉Token类工具快但不准,AST慢但稳,咋选啊
日本 B1
@ 古铜锁 一般先用Token筛一遍,误报多点再交给AST确认,折中还行 😂
湖南省株洲市 5F
吃瓜看大佬们卷克隆检测,我连Type1都还没整明白😂
安徽省合肥市 B1
@ 蓝鲸数据 其实Type1就是文字完全相同的块,直接用Token工具就能抓到,建议先跑个小样本感受下
浙江省 B1
@ 蓝鲸数据 我也是Type1都没整利索,先去补补基础算了
河南省洛阳市 B1
@ 蓝鲸数据 Type1太基础了,我连它都没弄清楚😂
澳大利亚 6F
PDG那个方法看着高大上,实际跑起来资源吃得消不?
日本 B1
@ Duskgazer PDG跑起来挺吃内存的,我们之前测Java项目直接OOM了😅
陕西省西安市 B1
@ Duskgazer PDG确实挺吃内存的,跑大项目得小心。
印度 7F
太老的工具链接好多挂了,能不能给个能用的合集?
贵州省贵阳市 B1
@ 幽灵低语 我试了几个,CCFinder和SourcererCC还能用,你要是找不到就直接去GitHub最新版吧
江苏省常州市 B1
@ 幽灵低语 试试CCFinder2、SourcererCC的最新仓库,基本能用。
湖南省怀化市辰溪县 8F
刚入门看了半天,Type3和Type4到底差在哪?有人通俗讲讲?
泰国 B1
@ 绯樱舞 Type3改变量名,Type4功能相同但实现不同。
福建省宁德市 9F
Nicad居然支持Python,回头试试,希望别崩
韩国 B1
@ 幽冥巫师 Nicad支持Python还行,不过偶尔会闪退。
日本 10F
Token类工具在Python上跑得飞快但一堆误报,烦死了
北京市 11F
这文章列的工具好多都年久失修了吧,GitHub点开404一片
河北省邯郸市 12F
Type3是改了变量名那种,Type4是代码完全不同但干同一件事,比如冒泡和快排都排序
浙江省宁波市 13F
CloneWorks试过,Python支持很弱,建议直接换Nicad试试
日本 14F
ML那几个看着牛,实际训练数据太难搞,根本落不了地
陕西省铜川市 15F
求问BigCloneBench现在还能下吗?官网连不上了急
陕西省西安市 B1
@ 思维云朵 BigCloneBench可在GitHub镜像下载,文件名BigCloneBench_v1。
北京市 B1
@ 思维云朵 BigCloneBench?之前github上好像有人fork了,搜搜看。
上海市徐汇区 16F
感觉克隆检测到最后都是工程问题,算法再好也架不住代码太野
印度 B1
@ 自在如风 代码太乱算法救不了,还是得先把结构整洁点,后面的检测才靠谱。
吉林省长春市 17F
这种工具太容易误报,真是烦人 😂
湖北省武汉市 18F
感觉AST慢但靠谱,选它吧。
湖北省 19F
ML方法听着高大上,实际部署好难。
浙江省 20F
我用了Nicad,Python支持还行,偶尔崩。
日本 21F
Token类跑得快,但同类代码的细粒度相似度经常漏掉,真让人纠结。
浙江省 B1
@ 逆天 确实,Token快但细粒度经常掉,建议先用它粗筛,再配合AST查细节。
天津市 22F
看到有人把PDG方法装进IDE里,结果占内存太高,机器卡死,建议先小规模试。
北京市 23F
之前在大项目里先用CCFinder排除明显克隆,再用CloneWorks找细粒度语义克隆,虽然步骤多点,但把潜在漏洞压下来,效果还不错。
北京市 24F
感觉Token快但误报多,真头疼。
北京市 25F
AST慢点,但靠谱,推荐。
江苏省徐州市 26F
ML工具听起来高大上,实际部署太麻烦。
天津市南开区 27F
老工具链接经常死,真是心累。
广东省东莞市 28F
我之前在大项目里先跑CCFinder筛选,再用CloneWorks细化,整体效果不错。
湖南省长沙市 B1
@ 芳华岁月 听起来不错,我正想尝试类似流程,尤其是先剔除明显克隆省时间。
印度尼西亚 29F
有人实测PDG在linux内核上跑,内存占用大不大?求经验。
菲律宾 30F
这玩意儿对Type4检测还是不太行啊,试过几个工具都漏得厉害
广东省佛山市 B1
@ 寂静之森 我试过CloneWorks配合PDG,虽然慢点但对Type4的漏报明显下降。😊
日本 B1
@ 寂静之森 Type4检测现在真不成熟,要不咱别太指望了😂
湖南省长沙市 31F
我之前在一个上千文件的Java项目里用了SourcererCC,虽然速度一般,但误报少,帮我找到了几个潜在的安全克隆,真是省了不少审计时间。
四川省成都市 32F
AST慢是慢,但真出了事还是得靠它查底。
泰国 33F
克隆检测这玩意儿,感觉像个玄学。
天津市 34F
ML那几个工具,光准备训练数据就得脱层皮。
日本 35F
求问Type4检测现在有能用的工具不?漏报太严重了。
上海市 36F
看到PDG就头疼,上次把服务器内存跑满了。
陕西省渭南市 B1
@ 老式挂钟声 我也遇到过,PDG占内存超乎想象,跑大项目前最好先抽样。
河南省周口市 37F
这么多工具,哪个对C++支持好点啊?
台湾省 38F
Token工具跑得快,适合先筛一遍,再用AST细看。
湖南省衡阳市 B1
@ 玄鬼行者 先用Token过一遍再上AST,这思路挺实用,省时间
广东省江门市 39F
能整理出这个工具列表,花了不少功夫吧。
澳大利亚 40F
工具链太老确实是个问题,好多链接都失效了。
上海市 41F
这么多链接,好多点开都404了,能用的没几个吧。
日本 42F
Type4检测现在到底行不行啊,有没有人实测过?
辽宁省大连市 43F
SourcererCC跑Java项目挺稳的,就是慢。
天津市 44F
看到PDG就想起上次服务器差点崩了,阴影。
新加坡 45F
这些学术工具,到实际项目里能用上的不多。
江苏省 46F
CloneWorks对Python不行,那对Go支持怎么样?
日本 47F
小白表示看不懂,有没有更简单点的入门教程?
河南省郑州市 48F
感觉这领域工具更新太慢了,跟不上现在语言版本。
江苏省泰州市 49F
Nicad试了下,配置有点复杂,有没有一键脚本?
山东省 50F
所以到底哪个工具综合来说最好用?给个推荐呗。
广东省深圳市 51F
Type4检测难啊,工具表收了
宁夏银川市 B1
@ Ripple涟漪 Type4的检测确实还在发展中,工具表希望能帮到你
湖南省益阳市 52F
感觉克隆检测到最后都是拼工程经验,工具只是辅助
上海市 53F
工具表很全,收藏了