首页> 中国专利> 发现受许可证约束的软件代码

发现受许可证约束的软件代码

摘要

实施例包括用于发现软件文件是否与许可证相关联的方法、设备和系统。软件执行的一个方法包括把软件划分为多个函数(120),把每个函数变换为多个标志(140),以及把所述多个标志与对应于已知函数的一组标志相比较(150),所述已知函数受软件许可证的约束。

著录项

  • 公开/公告号CN101093533A

    专利类型发明专利

  • 公开/公告日2007-12-26

    原文格式PDF

  • 申请/专利权人 惠普开发有限公司;

    申请/专利号CN200710112166.2

  • 发明设计人 N·克拉维茨;

    申请日2007-06-19

  • 分类号G06F21/22(20060101);

  • 代理机构72001 中国专利代理(香港)有限公司;

  • 代理人程天正;王忠忠

  • 地址 美国德克萨斯州

  • 入库时间 2023-12-17 19:32:51

法律信息

  • 法律状态公告日

    法律状态信息

    法律状态

  • 2020-06-23

    未缴年费专利权终止 IPC(主分类):G06F21/22 授权公告日:20101222 终止日期:20190619 申请日:20070619

    专利权的终止

  • 2017-02-15

    专利权的转移 IPC(主分类):G06F21/22 登记生效日:20170119 变更前: 变更后: 申请日:20070619

    专利申请权、专利权的转移

  • 2010-12-22

    授权

    授权

  • 2008-02-20

    实质审查的生效

    实质审查的生效

  • 2007-12-26

    公开

    公开

说明书

背景技术

开放源软件是公众能够免费获取来研究、使用、甚至修改的源代码或程序。这种代码在公众和软件开发者之间免费共享。由于该软件不是私有的,所以大批编程者能够修改并完善该源代码。经修改的软件被再发布给公众和其它编程者,以供广泛的软件应用。

通常,开放源软件不是商业开发并为了赢利而发布的,原因在于源代码是免费的。然而,与此同时,软件常常受到许可证形式的约束。开放源许可证使得用户能够获得免费的源代码,但是提供了能够限制源代码使用、修改和再发布的条款。这样的限制根据许可证的不同而变化,并且其范围从无限制的到完全限制的。例如,一些许可证仅仅要求用户保持原作者的姓名或者在实际源代码中包括版权声明。相对比而言,例如,其它许可证严格限制后续用户控告专利侵权、收集派生作品特许权以及为软件的修改版本授予许可证的权力。

由于一些开放源许可证能够是完全限制的,软件开发者和公司在把重要资源投入使用或修改源代码之前,必须复审并理解许可证的条款和条件。然而,该任务是非常困难的,原因在于代码能够包括一个或更多的受未知许可证约束的函数。作为一个例子,编程者能够在不承认管理原始函数的许可证的情况下,修改或重用函数并且接着释放该函数。例如,最初在一个许可证下释放的函数在没有许可证或者没有参考原始许可证的情况下被重用并释放。作为另一个例子,当私有代码受到一个或多个许可证的约束时,能够像开放源那样被重用或分类。此外,非私有代码或开放源代码能够随私有软件发布并由此违反开放源许可证。

软件代码的各部分能够由此受到一个或多个许可证的约束,即使这样的许可证不是随代码再生的或以代码为参考的。为了发现这样的许可证,人们可以尝试人工复审所有的源代码并将其与已知受到一个许可证约束的代码相比较。在假设代码的增殖、修改以及遍及世界的发布的情况下,该任务将是困难甚至不可能完成的。

附图说明

图1是根据本发明一个示例性实施例的确定代码是否受到一个或多个软件许可证的约束的示例性流程图。

图2是根据本发明一个示例性实施例的确定两个函数是否相似的示例性流程图。

图3A是根据本发明一个示例性实施例的比对(alignment)算法的第一示图。

图3B是根据本发明一个示例性实施例的比对算法的第二示图。

图3C是根据本发明一个示例性实施例的比对算法的第三示图。

图3D是根据本发明一个示例性实施例的比对算法的第四示图。

图3E是根据本发明一个示例性实施例的比对算法的第五示图。

图4是根据本发明的示例性计算机系统的模块图。

具体实施方式

根据本发明的实施例针对用于发现软件文件是否与一个或多个许可证相关联或者受到一个或多个许可证约束的设备、系统和方法。分析代码(例如源代码或编译对象)的一部分或者该代码中的函数,以确定其是否是受到一个或多个许可证约束的代码的相似派生品或修改。示例性实施例快速并准确地识别受到一个或多个软件许可证约束的代码,即使这样的许可证没有包括于所述代码或者由所述代码为参考也是这样。即使文件包括超过数万行的代码,依然能在代码中识别受到许可证约束的函数。这样的识别自动发生而只需很少或完全无需人为干预。

在一个示例性实施例中,复审一个或多个文件以确定这样的文件是否受到任何许可证或其它限制条款和条件的约束或被其所管理。文件的数目能够从一个文件到数十万个不同文件而变化。每个文件最初被分为一个或多个函数。所述函数被用于检查某些或特定术语的出现。这样的术语被普通术语所替代。每个函数接着被变换为一组标志(token)。对应于每个函数的标志被与对应于已知或预先存在的许可函数的标志组相比较。换言之,源函数的标志被与来自受到一个或者多个许可证的约束的已知函数的标志相比较。这种比较显示了源或候选函数与已知函数之间的相关性。确定是否存在匹配。如果存在匹配,则所述源函数(就像已知函数一样)被一个或多个预先存在或已知的软件许可证所管理。

在一个示例性实施例中,一种比对矩阵将源或候选函数与已知函数相比较。特别地,所述矩阵将两个符号序列互相比较。所述符号序列是从各个函数的标志组中得出的。系统确定两个序列是否类似(即相似)。该确定的结果被记录到日志中、保存和/或向用户输出。

图1是根据本发明一个示例性实施例的确定代码是否受到一个或多个软件许可证的约束的流程图100。根据模块110,接收或者获取一个或多个文件(称为候选、目标或源文件)或代码。所述代码包括源代码、编译对象和可执行代码,但是并不局限于此。例如,所述文件能够作为一个或多个软件发布包来进行发布。候选文件的数目从一个文件到数十万个文件而分布,例如在开放源软件包或开放源软件发布中存在的文件。

在这个时刻,确定是否任何目标文件是预先检查过的。在一个示例性实施例中,每个包和档案文件均被检查并与预先检查文件的知识基础(knowledge-bases)相比较。例如,如果一个包的特定版本的源代码已被处理过,则所述代码不会被再次处理,原因在于所述包的结果是预先确定的。

目标文件能够被“打包(packed)”或存档并且包括一个或多个嵌套或压缩格式的其他文件。每个包和存档文件被递归地解包直至不需要(例如,用数据、可执行代码和文本文件)进一步解包为止。对被解包的原始文件的参考被保存和记忆。在一个示例性实施例中,许多不同的文件格式是已知的或被用于递归解包。例如,这样的文件格式包括zip、tar、ar、cpio、gzip、bzip2、rpm、deb、rar、jar、cabinet文件、postscript以及uuencode/uudecode等,但并不局限于此。如果存档文件包含其它文件,则其被递归地解压缩和解包。一旦确定再没有文件需要解包,则解包终止。

根据模块120,代码或目标文件被划分或分割为函数。如此处所使用的,“函数”是执行特定任务的程序或代码的一部分。函数能够返回一个值,或者执行一个操作但不返回值。根据编程语言,函数具有不同的名字,例如子例程、方法、过程或子程序。此外,不同文件格式具有不同的方式来识别函数(例如,C语言中函数的符号与对象代码中的符号不同)。

根据模块130,每个函数中的一个或多个特定术语被一个或多个普通术语所替代。例如,每个函数中的所有变量(即标示数量的符号或符号表示)被单词“variable”或“var”或其它普通术语所替代。如另一个示例,每个函数中的所有数字被单词“number”或“num”或其它普通术语所替代。

根据模块140,每个函数被变换为一个或多个标志。如此处所使用的,词语“标志”表示文本、字符或具有含义的符号的分类块。例如,标志由不可分割的字符或语义(lexeme)组成。语义根据一个函数被读取和分类并且被提供一个含义,该过程称为“标志化(tokenization)”。如此处所使用的,词语“标志化”表示将输入字符的串的一个或多个部分划分界限并分类的过程。

根据模块130和140,根据特定的文件格式,函数被以不同的方式标志化。如所述,变量名被术语“variable”所替代并且术语“variable”在此后被看作一个关键词标志。此外,数字被术语“number”所替代,并且术语“number”在此后被看作一个关键词标志。标志化能够基于语言特定的关键词(例如,“if”或者“while”)、符号(例如,+、=、-、<、>等)和范围(例如,()、{}、[]等)而发生。例如,函数“a+b=b+7”具有标志“var+var=var+num”。如另一个示例,“call function(9)”具有标志“call var(num)”。此外,在一个示例性实施例中,标志的值不相关。

根据模块150,从目标函数中得出的标志被与来自已知函数的标志相比较。在一个示例性实施例中,已知函数包括受到一个或多个许可证约束或由其所管理的代码。

在一个示例性实施例中,获取或发现已知的或预先存在的软件许可证,例如开放源软件许可证。开放源文件受到数千个不同许可证的约束。这些许可证中的许多可以经互联网在开放源软件发布包中例如通过利用免费和开放源软件(Free and Open Source Software,FOSS)的组织并通过提倡开放源的组织获得。每个已知许可证具有一个或多个受一个或多个许可证的约束或被其所管理的文件。从而得知这些文件中的代码具有每个许可证的特定约束或限制。

如结合模块120所讨论的,一旦获取了已知文件,所述文件被划分为函数。如结合模块130所讨论的,函数中的某些术语被普通术语所替代。如结合模块140所讨论的,所述函数接着变换为一个或多个标志。

在这个时刻,至少存在两个不同的标志组或序列。第一组标志对应于目标函数(即,确定其是否受到已知许可条款的约束的函数)。第二组标志对应于比较或已知函数(即,预先已知受到软件许可证约束或受到限制条款和/或条件约束的函数)。模块150比较这两组标志序列。

根据模块160。确定在对应于目标函数的标志和对应于比较或已知函数的标志之间是否存在匹配。在一个示例性实施例中,为每一对函数,计算比对矩阵。识别所述比对矩阵中的最大值,并且确定是否存在匹配。例如,如果目标函数和比较函数之间的相似性或共性满足或超过一个阈值(例如,70%、80%或其它预先设定的值),则存在匹配。

根据模块170,把来自模块160的结果记录到日志中并保存。在一个示例性实施例中,将结果提供给用户(例如,作为报告输出到显示器,等等)。在一个示例性实施例中,把满足或超过一个阈值或具有预先定义的相似性的匹配记录到日志(例如,存储目标和已知函数的名称、匹配百分比、匹配和/或不匹配的确切标志,等等)。

图2是根据本发明一个示例性实施例的确定两个函数是否相似的示例性流程图200。结合图3A-3E(示出一系列示图,所述视图用于图示确定一个或多个源或候选函数是否受到一个或多个已知或预先存在的许可证的约束的示例性实施例)来讨论图2。示例中的每个不同字母表示一个不同的标志。使用符号比对矩阵将两个符号序列相互比较,并且确定这样的序列是否相似。

根据模块210,为源函数和比较函数计算一个或多个标志。该阶段在图1中的模块110-140更为详细的讨论。

在一个示例性实施例中,比较编译对象的两个部分以确定它们是否可能为来自相同源代码的派生品。该比较基于两个假设:(1)相同的源代码产生相同的操作代码,和(2)相同的操作代码序列由相同的源代码所创建。例如,当两个不同的软件开发者独立地创建了相同的功能性,它们的源代码很可能是唯一的并生成唯一的操作代码序列。当代码被用作模板,所述代码通常具有相似的表现形式,但却生成不同的操作代码序列。相对比而言,当源代码被再次使用(例如,借用、修改、被平衡(leveraged)、复制,等等),存在少量修改,但是主要功能元素保持相同。由于在此后一种情形中的代码主要是相同或等同的,所以所述代码生成相似的操作代码序列。根据本发明的实施例识别相似代码和类似功能性的部分或片断。

根据本发明的实施例能够利用一个或多个假设以分析代码,并确定候选代码和代码之间是否存在相似性。这样的假设包括以下几种:宏、内联代码、编译器最优化、代码重排序和软件开发者,但并不局限于此。宏能够启动或禁止不同的代码片断,特别是留在源代码中的调试语句。标示为“内联”的函数通常直接插入函数中。这些函数能够改变操作代码序列,但是却未必改变源代码的样子。关于编译器最优化,不同的编译器选项将操作代码序列修改为更好或最佳性能。关于代码重排序,如果两个代码片断S1和S2在源代码文件A中以[S1,S2]出现,而在不同的源代码文件B中以[S2,S1]出现,则根据本发明的实施例识别最大比对(如果|s1|>|s2|,则仅识别S1)。

如所注意的,还进行关于软件开发者的假设。虽然这些假设能够导致错误消极匹配,但是认为下列用于软件开发者的假设中的一个或多个是有效的。第一,开发者通常重新使用函数和非代码的单独行。第二,开发者可以对函数做少量改变,而不是对这样的函数做显著改变(显著改变典型地导致重新开发而不是重新使用)。第三,开发者通常不对重新使用的代码中的成分重排序。最后,开发者通常使用相似的编译选项。例如,大多数内核驱动器开发者对于相同的平台使用相同的编译器和编译器标记。

为了举例起见,比较A列表和B列表的两个序列。这两个列表均包含符号序列(串)。每个列表的长度分别标示为|A|和|B|。比对矩阵(表示于图3A-3E)标示为A×B。矩阵位置(a,b)表示A[a]和B[b]在A×B中的交叉点。

一个示例性实施例确定A中的符号与B中的符号对准的百分比,以及B中的符号与A中的符号对准的百分比。这些百分比标示为A*B和B*A。例如,如果A*B为60%,则A中60%的符号与B中的符号对准。A*B和B*A很可能不同,除非A和B完全相同并具有相同长度。

当两个序列在相似顺序上具有相似元素时,所述两个序列是类似的。类似性是一个两个序列是类似的或者是不类似的定性描述(这样,在一个示例性实施例中,不存在“60%类似”的值)。与之相比,相似性是一个定量描述。两个序列可以是60%相似的,并且也可以被认为是类似的。类似性定义相似性的阈值。此外,类似性是不对称的。换句话说,当B不类似于A时,A能够类似于B。当|B|比|A|大时能够发生该情形。再此外,子集能够是类似的。例如,A可能不类似于B,但是子集“a”却有可能类似于“b”。

在一个示例性实施例中,系统假设相似的序列产生相似的功能性。该概念随符号存在,例如源代码行或反编译的操作代码序列。根据本发明的实施例由此允许比较平台独立的序列。

在一个示例性实施例中,比对算法使用下列三个阶段或步骤中的一个或多个:初始化、同等识别(identical identification)和比对。这三个阶段表示于图3A-3E。

根据模块220,为源函数和比较函数计算比对矩阵。该阶段结合图3A和3B图示。

图3A示出比对算法的最初的或初始化阶段。最初,把符号或序列对准在矩阵中。为了举例,为A选择符号“cheloe”,为B选择符号“hello”。如所示,A的符号(cheloe)被垂直排列于矩阵上,而B的符号(hello)被水平排列于矩阵上。矩阵的每个单元最初为空白或者0。

图3B示出同等识别阶段。在此,如果A[a]与B[b]相同,则矩阵A×B中的每个位置标记为“1”。如果A[a]与B[b]不相同,则该单元或矩阵坐标为空白(或标记为“0”)。这样,图3B示出A[a]与B[b]相同的六个不同位置(即,(2,1)、(3,2)、(4,3)、(4,4)、(5,5)和(6,2))。

根据模块230,在比对矩阵中识别出最大值。接着,根据模块240,如果在源函数和比较函数之间存在相似性,则识别出匹配。在一个示例性实施例中,此相似性至少部分地基于一个或多个阈值。图3C-3E示出模块230和240的比对阶段。

首先,如图3C所示,矩阵中的每个单元被更新为其自身与子矩阵[(0,0),(a-1,b-1)]中最大值之和。这样,表元素(3,3)在图3B中最初为0或空白。然而,在图3C中,此表元素(即,对应于字母“l”和“e”)被更新为值1,原因在于子表[(0,0),(1,1)]中的最大值为1。相似地,代表“l”דl”的表元素(2,3)获得值3。对于单元(2,3):等同+max[(0,0),(1,2)]=1+2=3。

图3D示出矩阵中的每个单元更新为其自身与子矩阵[(0,0),(a-1,b-1)]中最大值之和后的最终表。如所示,外边缘上的最大值(即,4)表示已对准的字符的最大数目。这样,就有4个已对准的字符。

图3E示出最佳对准路径。特别地,分配给最大值的单元(沿箭头所示)表示最佳对准路径。在该示例中,所述路径表示:(1)“4”来自于“o”;(2)“3”来自于“l”(即,对于“hello”仅有两种选择,而对于“cheloe”有一种选择);(3)“2”来自于“e”(“cheloe”中的第一个“e”);和(4)“1”来自于“h”。水平和垂直间隙确切地示出那些符号对准:(1)“cheole”与“_helo_”对准,和(2)“hello”与“hel_o”或“he_lo”对准(如图所示)。此外,对于对准的百分比:(1)“cheloe”与“hello”的80%对准(即,4/5符号),和(2)“hello”与“cheloe”的67%对准(即4/6符号)。

如果|A|要比|B|大得多,则B很可能具有相对大的百分比,而A则具有相对低的百分比。如果A和B都是非平凡的(即,都相对大)并且都具有高相似度,则它们很可能互为变量。例如,阈值80%表示序列被重用并且由此对应于受一个或多个许可证约束的已知或预先存在的函数。

根据本发明实施例的示例性实施例比较单个字母或符号。例如,如果串是同样的,则认为两个元素是相同的。在一个实施例中,所述串是来自于代码(例如源代码、反编译的汇编代码等)的行。

根据模块250,相似的匹配被记录入到日志、存储和/或提供给用户。在比较之后,存在一个匹配列表。该列表示出详细的匹配(例如,下至函数级别)并提供一个或多个概要、范围、模式等。所述日志可包括与多个标志之间的极端匹配。小标志能够包括十二个或更少标志。较大的标志可包括数百或数千个标志。从而,匹配能够包括几个标志或数千个标志。在一个示例性实施例中,当匹配标志的总数(来自所有函数比较)大于特定阈值时(例如,大于一千个标志),所有的文件被识别为匹配。

所述日志还可包括与多个函数之间的极端匹配。例如,编程者将经常从代码复制多于一个的函数(他们经常复制或修改许多函数)。因此,进行检查或验证以确定是否许多函数(甚至是具有很少标志的函数)表现为源自于相同的文件。如果两个文件具有相似的函数,则它们很可能是相似的。在一个示例性实施例中,一个阈值约为10。例如,如果两个文件之间有≥10个相似函数,则它们很可能是由于代码重用的原因。

根据本发明的实施例比较两个或更多函数(或从函数得出的标志集合)以确定函数之间的相似性。给定相同语言的两个源代码文件,确定是否存在相似函数。此外,本发明的实施例也能够应用于二进制文件和文本文件。例如,给定两个二进制文件,确定对象代码是否相似。在此,相似的操作代码序列通常要求相似的源代码。对于文本比较,每个段或文本块被看作函数。每个单词为标志(例如,使用不区分大小写的方法并去除非单词字符)。

根据本发明的实施例由此创建基于语言(源代码、二进制文件、文本等)的标志。如以下所述,示例性实施例也为许多不同的函数做了最优化的。

根据本发明的实施例确定两个函数是否相似或匹配并不局限于任何特定标准、阈值、数字、因素等。在一个示例性实施例中,给定矩阵A×B(例如,如结合图3A-3E所注意的),当(1)A*B至少约80%到90%;(2)B*A至少约80%到90%;(3)两个集合中的至少10个符号匹配(该情形阻止了在匹配中由短集合生成错误-消极);和/或(4)对准的序列之间的间隙不超过5个符号宽度(例如,“hello”与“hel_o”对准表示一个符号的间隙),就确定是类似性匹配。

在一个示例性实施例中,为了降低来自大型循环的影响,比对矩阵算法被最优化。遍历所述矩阵不超过一次。最优化算法的复杂度为O(|A|·|gB|),gB为序列B最大间隙的大小。gB的大小不大于|B|,并且通常显著小于|B|。例如,对所述算法的最优化包括一个或多个字节流水线传送(byte pipelining)、子矩阵扫描、间隙截断(gap truncation)、比较限制、比较截断、比较忽略和串比较。此外,编程惯例最优化包括一个或多个矩阵存储器分配和预处理相对高速缓存(preprocessingversus caching)。

在字节流水线传送中,矩阵被布局为大型阵列:(a,b)=AxB[a]·|B|+b]。使用该布局,沿B轴的所有字节都是顺序的。这种排列允许由于线性存储器访问的数据流水线传送。

在子矩阵扫描中,使用矩阵中的各种传递(例如分配0/1值的第一传递,更新单元的第二传递,扫描子矩阵的第三传递)。在最优代码中,仅使用一个传递来通过整个矩阵。算法的填充属性之一沿着外边缘放置任意子矩阵的最大值。这样就无需扫描任意子矩阵的内部;而仅需要扫描外边缘。在一个示例性实施例中,所述算法为:

对于每个单元(a,b)

沿着外边缘查找最大值

边缘#1:[(0,b-1),(a-1,b-1)]

边缘#2:[(a-1,0),(a-1,b-1)]

把最大值添加到等同检查:A[a]=B[b]?

把该值存储到该单元中

结果是为确定任意子矩阵的最大值而扫描的单元明显减少。

在间隙截断中,对准符号之间的最大允许间隙可被用作限制。当确定矩阵位置(a,b)的值时,子矩阵扫描仅检查子矩阵的外边缘:[(a-1,0)至(a-1,b-1)]和[(0,b-1)至(a-1,b-1)]。对于a或b中相对较大的值,该扫描需要相对大量的时间。作为最优化,扫描对应于间隙的边缘。例如,如果最大允许间隙为3,则所述子矩阵扫描减少至[(a-1,b-4)至(a-1,b-1)]和[(a-4,b-1)至(a-1,b-1)]。

在比较限制中,示例性实施例识别最优匹配。如果最小匹配值相对较大,则仅仅沿矩阵的中对角线的单元与匹配有关。这样,与匹配无关的单元无需扫描。例如,假设两个20的序列相比较,并要求90%匹配。所述匹配仅要求最大值不小于16(即,20的90%)。

在比较截断中,以对A序列的最小要求匹配沿B轴对矩阵进行扫描。特别地,对于任意列“a”,验证或检查最大“b”矩阵值是否足以导致匹配。当不可能匹配时,跳过矩阵的剩余部分。

比较忽略与比较限制的相似之处在于,如果|A|和|B|明显不同,则可能不会匹配。例如,如果两个序列均必须90%匹配,但是|A|<90%·|B|,则这两个序列不匹配。这样,跳过整个矩阵的填充和比较。

在串比较中,符号被存储为串。不过,strcmp()不是一个快速函数。为了减少strcmp()调用的数量,每个串以一字节的校验和(串中所有字节的和)作为前序。对于多数比较,所述校验和的值不同,表示strcmp()不匹配并且无需被调用。当串相同或存在校验和冲突时,仅发生对strcmp()的调用。

在大型序列中,分配和初始化矩阵可能需要重要的处理资源。在一个示例性实施例中,最优化矩阵存储器。在初始化中,所述矩阵既未分配也没有初始化,除非存在所述矩阵导致匹配的机会。如果序列大小不同以致于使得它们不能导致成功的对准,则所述矩阵不需要被访问。在再分配中,当处理每个文件多个序列时,所述矩阵不被再分配,除非其需要是更大的。例如,如果第一比较需要400个单元,第二比较需要96个单元,则矩阵存储器在顺序调用之间既不被释放也不被再分配。所述矩阵仅当该比较需要400个单元时才被再分配。在组织中,所述矩阵被分配为单个阵列而不是二维结构。该实施例允许重用而无需考虑序列的大小。例如,20×20的矩阵和10×40的矩阵均能够使用相同的分配的矩阵。

在一个示例性实施例中,过滤函数将输入文件转换为符号集合。从而,过滤器将所需数据转换为符号序列。例如,操作代码过滤器将编译的对象的可执行体转换为具有已识别函数的符号序列。该过滤器在多个阶段之中操作(例如获取操作代码,识别函数和去除常数)。

在初始化阶段,获取操作代码。例如,所述过滤器在可执行体或对象代码上运行命令“objdump-d”。参数“-d”将操作序列译码为汇编语言。反汇编器显示每个函数名和函数内的操作代码,每行一个汇编代码。

在第二阶段期间,去除非函数和二进制代码。例如,每个函数名被以单词“Function”和新行作为前序。所述新行允许算法识别下一个函数代码的开始。在一个示例性实施例中,每个汇编行被以一周期为前序,由于一些函数包含没有被解析为文本操作代码的填充(例如,0的序列)。若没有初始周期,则填充行会作为新行出现且不会正确地指示下一个函数的开始。

在第三阶段期间,从代码中去除约束。被反汇编的代码包括链接时间约束,当重用所述代码,链接时间约束可以变化。在一个示例性实施例中,去除所有的常量值。

来自过滤器的结果是伪唯一的(pseudo-unique)汇编命令集合。对于大型序列(10个或更多汇编行),两个不同函数具有类似部分而不具有代码重用的可能性显著地降低。

根据本发明的实施例并不局限于任何特定类型的过滤。如果被实现,过滤技术部分取决于特定的软件语言。由于大多数Linux内核源代码以ANSI-C书写,所以提供了过滤C语言的示例性实施例。

作为一个观察,当编程者使用C源代码时,他们通常生成以下格式化变化中的一个或多个:(1)改变诸如制表符和缩进之类的白空间;(2)增加、修改或去除注释;(3)改变变量和附属函数名;(4)改变诸如串或常量之类的静态值;(5)增加附加行或去除现有行。

作为另一个观察,当编程者使用C源代码时,他们通常不会改变以下的一个或多个:(1)标志的数目和相对位置(例如,符号、圆括号、范围、数学运算符)保持类似;(2)变量、串和函数的数目和相对位置保持类似(例如,代码重用可以改变函数的名称,但函数却很少被改变为变量或串);以及(3)函数参数的数目和类型保持类似。

在一个示例性实施例中,C源代码的过滤器运行于几个不同阶段,包括:(1)去除注释和标记范围;(2)识别函数;(3)替换参数;以及(4)去除标记;但并不局限于此。

在第一阶段期间(即,去除注释和标记范围),将整个源文件加载到存储器中。当所述文件加载后,用以下中的一个或多个对数据进行预处理:(1)去除所有ANSI-C注释;(2)去除所有C++注释;(3)去除所有编译器指示;(4)去除新行;(5)识别开始和结束引号和双引号;(6)以当前范围深度标记新范围。该预处理的结果为包括所有活动源代码对象的单个行。所述行包括识别匹配范围和串的标记。

在第二阶段期间(即,识别函数),函数作为单词空间出现,之后跟随一组0范围圆括号“(0...)0”和一组0范围大括号“{0...}0”。去除所有非函数元素。所去除的项包括函数原型、结构定义、全局变量、宏、函数返回参数定义和所去除的圆括号和大括号之间的任意变量定义,但并不局限于此。该阶段的结果是包含函数名和函数范围的长串。

作为第二阶段的子集,进行标志分离。C预分析器(preparser)允许一些标志与变量或函数名相邻。为了简化过滤过程,将标志清楚地分离开。一些示例包括分号(每个分号之前或之后添加有空间)、逗号,++和--赋值操作符被填充有白空间,所有的单词标志被填充有白空间。由于一些项目被错误分离,可增加第二阶段来替代一些项目(例如,任何由数字所跟随的范围把空间去除掉了,并且连接了复杂的变量)。

作为第二阶段的另一个子集,进行变量替换。所有的变量和函数名由单词“var”所替换。对于类似比较,变量的重用并不重要(仅仅是变量的频率和位置而已)。虽然此替换不会在变量和函数之间造成差异,但是函数仍然能够被“var”串之后的圆括号所识别。在一个示例性实施例中,仅仅没有被替代的变量才是特定于C语言的串。

作为第二阶段的另一个子集,进行串替换。例如,替换所有用“<...>”和‘<...>’的串。双引号用文本“string”所替代,而单引号用“char”所替代。相似地,数字(用[0-9]+或0x[0-9]+所标示)用“num”所替换。

作为第二阶段的再另一个子集,进行变量定义去除。在一个示例性实施例中,该子集在函数内包括四类动作:(1)赋值:a=b,a++;(2)运算符:a>b,a+b;(3)函数:a;(4)声明:int a。在一个示例性实施例中,声明仅仅是函数内的几行,这几行不生成任何操作代码序列。

在第三阶段期间(即,替换参数),注意到参数“(0...)0”可能在函数定义内。在代码重用期间,参数类型(“int”或“struct complex*”)和变量名能够变化。同时,参数的数目保持类似。可以增加或去除几个参数,但是参数的总数保持相同。在一个示例性实施例中,每个参数(原型和名称)用单词“parm”所替代。例外是被去除的空参数。

在第四阶段期间(即,去除标记),注意到重用的源代码能够包括附加范围。为了防止范围标记被使用,去除所有的范围深度标记。例如,“{0...}0”变为“{...}”。

在第四阶段之后,最终的结果是包含函数名和标志的文件,每行一个标志。此外,在过滤之后,代码仅包含指示C标志、变量和串的符号。再此外,每个函数的符号序列是每个代码功能性的伪唯一。对于大型序列,两个诸多不同的函数具有相似标志序列的机会变得非常小。

使用根据本发明的实施例,在许可证复审过程中对人为干预的需显著地减少了,其原因在于目标函数与比较函数被比较以确定目标函数是否受到一个或多个已知或预先存在的软件许可证的约束。一旦生成输出(例如,在报告中显示或打印),复审者能够轻易复审数千个文件以确定是否有什么文件包含受许可证约束的代码。

根据本发明的实施例被用于各种系统、方法和设备。图4图示了作为计算机系统400的示例性实施例,其用于利用根据本发明实施例的一个或多个流程图和/或方面。

系统400包括主机计算机系统420和知识库、仓库或数据库430。所述主机计算机系统420包括处理单元450(例如一个或多个中央处理单元的处理器,CPU),用于控制存储器460(例如临时存储数据的随机访问存储器(RAM)和持久存储数据的只读存储器(ROM))和算法470(可置于存储器460或其它位置)的整体操作。所述存储器460例如,存储数据、控制程序和与主机计算机系统420相关联的其它数据。所述处理单元450通过总线490与存储器460、数据库430、算法470(例如比对算法)和许多其它部件进行通信。这些算法包括图1和2的流程图及其变化,但并不局限于此。

根据本发明的实施例并不局限于任何特定类型或数量的数据库和/或主机计算机系统。例如,所述主机计算机系统包括各种便携式和非便携式计算机和/或电子装置。示例性主机计算机包括计算机(便携式和非便携式)、服务器、大型计算机、分布式计算设备、膝上型电脑和其它电子设备和系统(无论这种设备和系统是便携式和非便携式的都是如此),但并不局限于此。

如在此使用的,术语“源代码”意味着以特定编程语言书写的程序指令。此外,如在此使用的,术语“开放源”指对于普通公众可免费获取来使用或修改的程序或源代码。此外,如在此使用的,术语“许可证”意味着授予某团体使用知识产权的明确权力的契约或条款以及条件。因此,为了使用、修改或再发布开放源,开放源许可证向许可证颁发者声明条款、条件和/或限制。开放源通常包括或受到开放源许可证的约束。例如,这样的许可证关于如何使用、发布或修改源代码,能够规定不同的标准和限制。例如,一些标准包括但并不局限于以下:许可的软件不能在以许可的软件所发布的其它软件上执行限制,所有人平等访问软件,对软件的权力在作为特定软件发布的部分的软件上并不是暂时的,作者必须允许修改或派生作品并保持原始名称,禁止程序发布的收集和特许权,以及禁止试图反对特定领域的说明。

在一个示例性实施例中,流程图中的一个或多个模块是自动的。换句话说,设备、系统和方法自动发生。如在此使用的,术语“自动的”或“自动地”(以及其变化)意味着使用计算机和/或机械/电子装置控制设备、系统和/或过程,而无需人为干预、观察、花费精力和/或决策。

提供根据本发明实施例的流程图作为示例,而不应被认为是对本发明范围内其它实施例的限制。例如,各模块不应被解释为是必须以特定顺序执行的步骤。可以增加附加模块/步骤,去除一些模块/步骤,或改变模块/步骤的顺序,仍然属于本发明的范围。此外,不同附图中的模块可以加入其它附图,或者与其它附图的模块交换。再此外,应当理解的是,特定数字数据值(例如特定数量、数字、种类等)或其它特定信息是说明性的,用于讨论示例性实施例。这种特定的信息并不是提供来限制本发明的。

在根据本发明的各个实施例中,实施例被实现为方法、系统和/或设备。如一个示例,示例性实施例被实现为执行在此所描述的方法的一个或多个计算机软件程序。所述软件被实现为一个或多个模块(也看作代码子例程,或面向对象编程中的“对象”)。所述软件的位置对于各种不同的实施例能够是不同的。例如,所述软件编程代码由计算机或服务器的处理器或多个处理器从一些类型的长期存储介质中访问,所述长期存储介质例如CD-ROM驱动器或硬盘。所述软件编程代码收录或存储于任意已知的介质,用于与数据处理系统或在任何存储器装置中来使用,所述存储器装置例如半导体、磁和光装置,包括磁盘、硬盘、CD-ROM、ROM等。所述代码分布于这样的介质上或发布给用户,从计算机系统的存储器或存储中通过一些类型的网络发布到其它计算机系统,由这些其它系统的用户使用。作为选择,编程代码收录于存储器(例如手持便携式电子装置的存储器)中并由处理器通过总线访问。将软件编程代码收录在存储器中、物理介质上和/或通过网络发布软件代码的技术和方法是公知的,在此不再进一步讨论。

以上讨论试图说明本发明的原理和各个实施例。一旦充分理解以上公开,多种变化和修改对于本领域技术人员就会变得显而易见。以下权利要求试图包括所有这样的变化和修改。

去获取专利,查看全文>

相似文献

  • 专利
  • 中文文献
  • 外文文献
获取专利

客服邮箱:kefu@zhangqiaokeyan.com

京公网安备:11010802029741号 ICP备案号:京ICP备15016152号-6 六维联合信息科技 (北京) 有限公司©版权所有
  • 客服微信

  • 服务号