一种基于抽象语法树的Python程序类型缺陷检测方法转让专利

申请号 : CN201710376265.5

文献号 : CN108932192B

文献日 :

基本信息:

PDF:

法律信息:

相似专利:

发明人 : 陈林刘畅徐兆桂徐宝文

申请人 : 南京大学

摘要 :

本发明提供一种基于抽象语法树的Python程序类型缺陷检测方法,包括下列步骤:1)收集Python软件缺陷报告信息,提取缺陷标识符和缺陷错误类型;2)获取缺陷修复前后两个版本程序的源代码;3)生成两个版本源代码对应的抽象语法树,匹配获取变更函数结点并标记缺陷错误类型;4)根据变更函数结点上下文信息,生成缺陷代码的特征向量;5)利用机器学习技术,在缺陷代码特征向量上训练多分类模型;6)提示开发者在测试Python程序文件中可能出现的类型缺陷信息。本发明旨在解决目前存在的缺乏针对Python语言的类型缺陷分析、无法检测可能的缺陷错误类型等问题,进而指导软件质量的管理,提高软件的可维护性。

权利要求 :

1.一种基于抽象语法树的Python程序类型缺陷检测方法,其特征在于,从软件缺陷追踪系统中获取Python软件中已被修复的缺陷报告信息,并从软件版本控制系统中获取相应Python软件修改前和修改后两个版本的源代码,生成两个版本源程序对应的抽象语法树,匹配抽象语法树,寻找发生变更的函数定义结点,结合从缺陷报告的摘要和描述中抽取的错误类型信息,为函数定义结点标记相应的错误类型,根据函数结点内赋值语句的相关信息生成特征向量,通过机器学习技术在特征向量与错误类型的关系上建立分类模型,对新的Python程序源代码给出可能引发缺陷的函数以及错误类型;该方法包括下列步骤:

1)收集Python软件缺陷报告信息,提取缺陷标识符和错误类型;从软件缺陷追踪系统中收集Python软件中已被修复的缺陷报告信息,包括缺陷标识符、摘要和描述;判断以下9种Python错误类型是否在摘要和描述中出现:ArithmeticError,AttributeError,KeyError,IndexError,IOError,NameError,SyntaxError,TypeError,ValueError;并将其中出现的错误类型加入错误类型列表;

定义1:缺陷标识符是缺陷追踪系统中的唯一数字序列,代表一个特定的缺陷;

2)获取缺陷修复前后两个版本程序的源代码;根据步骤1)中获取的缺陷标识符,从软件版本控制系统的提交记录中找出修改的文件名和对应的修复版本号,并根据文件名和版本号从软件版本控制系统中下载缺陷修复前后两个版本的源代码;

定义1:提交记录是软件版本控制系统中开发者提交程序代码时记录的历史信息,包括提交日期、版本号、开发者姓名、本次提交中修改的文件以及开发者的注释信息,如果该提交修复一个缺陷,则提交记录中会包含缺陷标识符;

定义2:文件名和版本号是软件版本控制系统中用于区分不同软件或同一软件不同版本的标识;

3)生成两个版本源代码对应的抽象语法树,匹配获取变更函数定义结点和未变更函数定义结点并分别标记错误类型;对步骤2)中的包含缺陷的源代码和修复后的源代码进行词法分析和语法分析,利用Python标准库中的ast模块生成抽象语法树,并设置label和value,标识结点类型和内容,同时设置结点标识符;后序遍历两个版本的抽象语法树,依次匹配各个对应结点,寻找缺陷版本源代码对应的抽象语法树中的changed_node以及unchanged_node,使用由步骤1)获取的错误类型列表中的错误类型对changed_node进行标记,使用NoError对unchanged_node进行标记,对于抽象语法树中的FunctionDef结点,使用元组δ=(结点标识符,错误类型列表)记录结点引发错误的情况;

定义1:抽象语法树是源代码抽象语法结构的树状表现形式,每个结点代表源代码中的一种结构;

定义2:Python标准库随Python语言一起发行,包含了诸多能提供系统级功能访问的内建模块;

定义3:ast模块是Python标准库中的一个模块,帮助解析Python抽象语法;

定义4:label表示抽象语法树中结点的类型,类型信息来自Python抽象语法;

定义5:value表示结点的内容,中间结点的value依赖于其label,如赋值语句的value,叶子结点的value即语句的文本表示,如函数调用语句等;

定义6:结点标识符用于唯一标识结点,每个结点不同;

定义7:FunctionDef是ast模块中的一种结点类型,表示函数定义;

定义8:changed_node表示抽象语法树中发生变更的且结点类型为FunctionDef的结点;

定义9:unchanged_node表示抽象语法树中未发生变更的且结点类型为FunctionDef的结点;

定义10:NoError表示结点未发生错误;

4)根据变更函数结点上下文信息,生成缺陷代码特征向量;使用树的中序遍历方式遍历步骤3)中得到的func_def,得到assign_list,统计assign_list中所有出现过的变量名,构成name_list;针对name_list中的每个name,使用pysonar2统计name在func_def中出现过的不同类型的个数,得到func_def中每个name与其类型种类数的映射,构成map;对assign_list中的每个assign_item,记录所有位于赋值符左侧的变量名,构成left_names,并记录所有为与赋值符右侧的变量名,构成right_names,然后通过计算assign_len,min_name_len,max_category,max_call和all_checked,得出缺陷代码特征向量Δ;

定义1:func_def表示抽象语法树中结点类型为FunctionDef的语法结点;

定义2:Assign是ast模块中的一种结点类型,表示赋值;

定义3:assign_list表示赋值结点列表,列表中的元素是赋值结点,其类型为Assign;

定义4:name_list表示变量名称列表,列表中的元素是变量名称;

定义5:name是name_list中的元素,表示变量名称;

定义6:map是由name_list中的name与其类型种类数的映射关系构成的哈希表,哈希表中的每个元素为变量名和类型种类数的映射,形式为:map={name1:n1,name2:n2,...,namek:nk}

定义7:assign_item是assign_list中的元素,表示一个赋值结点;

定义8:left_names是由assign_item中所有位于赋值符左侧的变量名构成的变量名列表;

定义9:right_names是由assign_item中所有位于赋值符右侧的变量名构成的变量名列表;

定义10:astunparse是Python语言的一个模块,可用于将ast中的语法结点转换为相应的Python源代码;

定义11:assign_len是将assign_item转换成Python源代码程序后所对应的赋值语句的长度;计算过程为:使用astunparse模块将assign_item反向解析,得到对应的源代码字符串,然后利用Python中的len方法对该字符串进行求值,得出赋值语句的长度;

定义12:min_name_len表示left_names中所有变量名长度的最小值;

定义13:max_category表示right_names中变量名对应类型种类数的最大值;

定义14:max_call表示在right_names中的变量名上所直接施加的方法调用次数的最大值;

定义15:all_checked表示right_names中的变量在使用前是否均被执行过类型检查,取值为1或0;计算过程为:使用树的深度优先遍历方法确定func_def到assign_item的路径,得出路径中除func_def和assign_item的所有结点,构成路径结点集合,获取路径结点集合中使用Python内置方法type()或instance()进行操作的结点,提取在这些结点上被传入type()或instance()的不同变量名,记为distinct_names;若right_names为distinct_names的子集,则all_checked为1,否则为0;

定义16:缺陷代码特征向量Δ是由assign_len,min_name_len,max_category,max_call和all_checked组成的特征向量,形式为:Δij=[assign_lenij,min_name_lenij,max_categoryij,max_callij,all_checkedij]其中,i=1,2,...,M;j=1,2,...,N;M为抽象语法树中的函数定义结点数,N为函数结点中赋值结点的个数;

5)利用机器学习技术,在缺陷代码特征向量上训练多分类模型;根据步骤4)中的缺陷代码特征向量及其对应的缺陷错误类型,生成训练集,训练多分类Logistic回归模型;

定义1:多分类Logistic回归模型是通过一系列连续型或类别型预测变量来预测多值型相应变量的模型,是二分类Logistic回归模型的扩展;记y是因变量且有c种取值,从0到c-1,自变量x=(x1,x2,...,xp)是我们采集到的缺陷代码特征向量,则可以得出y的条件概率:其中,k=0,1,2,…,c-1;由此得到多分类Logistic回归模型:

其中, 是回归系数;

6)提示开发者在测试Python程序文件中可能出现的缺陷信息;对于一个新的Python程序文件,应用于步骤5)中得到的多分类Logistic回归模型,提示开发者在程序中可能引发缺陷的函数,以及可能的缺陷错误类型。

说明书 :

一种基于抽象语法树的Python程序类型缺陷检测方法

技术领域

[0001] 本发明属于计算机技术领域,尤其是软件技术领域,且特别是有关于一种基于抽象语法树的Python程序类型缺陷检测方法。

背景技术

[0002] 软件缺陷是计算机程序或系统中存在的、会破坏软件正常运行能力的问题或错误,是系统所需要实现的某种功能的失效或违背。在软件开发和维护过程中,由于各种因素的影响,软件缺陷很难避免,而且会经常出现。在软件开发阶段,软件缺陷伴随着软件开发流程的各个过程,需求分析中如果没有充分弄清需求将会带来很多不必要的软件缺陷,开发过程中若没有采用优秀的管理方法也会导致很多软件缺陷。在软件维护阶段,审查和修复软件缺陷需要投入大量人力物力。有研究表明,在软件项目的整个生命周期中,软件维护成本占到总成本的75%以上,并且找到缺陷比修复缺陷更加困难,需要花费更多的时间。
[0003] 软件缺陷的引发原因还与开发过程中所选择的编程语言相关。一般说来,使用静态编程语言编写的软件产生缺陷的几率要小于动态编程语言。这是因为,静态语言编写的程序一般经过预处理、编译、汇编、链接等步骤,编译器会在程序运行之前对程序中代码的变量进行严格的类型检查,确保在变量的使用方式与其定义一致,同时保证程序运行时变量的类型不发生改变。相比之下,动态语言中对象的类型是在运行时决定的,且可以随时改变,如果对象的类型变化得过于频繁,则无法完全保证对象在运算过程中拥有的类型与我们预期相符,加大了在对象使用过程中引发缺陷的概率。
[0004] 在所有动态类型编程语言中,Python借助其强大的功能,在数值计算、机器学习、Web开发等领域都有着广泛的应用。在软件开发过程中,Python语言的动态特性为开发人员带来了极大的灵活性,其对类型的检查是在运行时完成的,允许开发者动态地更改对象的类型。这种在更高抽象级别进行编程,而不必考虑对象具体类型的方式,使得开发更加高效。然而,由于缺少静态类型检查,Python程序中一些潜在的缺陷很难在程序运行前被检测出来,这为软件维护增添了许多负担。因此,为帮助人们尽早发现Python程序缺陷,越来越多的静态检查工具(如PyChecker、pylint)得到使用。这些工具提供了丰富的用户自定义选项,可以在Python代码运行前帮助检测出许多bug,例如函数调用时传给函数的参数个数不正确,使用与格式字符串不匹配的参数,使用类中不存在的方法或属性等。然而这些工具不能通过静态分析的方式,分析Python代码中何处会由于类型变化过于频繁而导致程序运行时报错,更无法提供这种缺陷可能引发的缺陷错误类型。

发明内容

[0005] 本发明提供了一种面向Python语言的、基于抽象语法树的类型缺陷检测方法,该方法通过匹配缺陷版本和修复版本Python源代码对应的抽象语法树,结合缺陷追踪系统的缺陷报告,确定程序中每一处引发缺陷修复的错误类型,使用成熟的机器学习技术从缺陷修复信息中学习分类规则,预测程序中可能出现缺陷的位置以及可能的缺陷错误类型。本发明旨在解决目前存在的缺乏针对Python语言的类型缺陷分析、无法检测可能的缺陷错误类型等问题,进而指导软件质量的管理,提高软件的可维护性。
[0006] 为达成上述目的,本发明提出一种基于抽象语法树的Python类型缺陷检测方法。方法包括下列步骤:
[0007] 1)收集Python软件缺陷报告信息,提取缺陷标识符和缺陷错误类型;
[0008] 2)获取缺陷修复前后两个版本程序的源代码;
[0009] 3)生成两个版本源代码对应的抽象语法树,匹配获取变更函数结点并标记缺陷错误类型;
[0010] 4)根据变更函数结点上下文信息,生成缺陷代码的特征向量;
[0011] 5)利用机器学习技术,在缺陷代码特征向量上训练多分类模型;
[0012] 6)提示开发者在测试Python程序文件中可能出现的类型缺陷信息。
[0013] 进一步,其中上述步骤1)的具体步骤如下:
[0014] 步骤1)-1:起始状态;
[0015] 步骤1)-2:获取缺陷追踪系统中已被修复的缺陷报告;
[0016] 步骤1)-3:从已被修复的缺陷报告中,提取缺陷标识符、摘要及描述等相关信息;
[0017] 步骤1)-4:从摘要和描述信息中,提取已被修复的缺陷错误类型;
[0018] 步骤1)-5:缺陷报告信息采集完毕。
[0019] 进一步,其中上述步骤2)的具体步骤如下:
[0020] 步骤2)-1:起始状态;
[0021] 步骤2)-2:根据缺陷报告中提取的缺陷标识符,从软件版本控制系统中获取包含该缺陷标识符的提交记录;
[0022] 步骤2)-3:根据提交记录中的版本号获取缺陷修复前后两个版本程序的源代码;
[0023] 步骤2)-4:软件缺陷源代码信息采集完毕。
[0024] 进一步,其中上述步骤3)的具体步骤如下:
[0025] 步骤3)-1:起始状态;
[0026] 步骤3)-2:为缺陷版本程序的源代码和修复版本程序的源代码分别生成抽象语法树;
[0027] 步骤3)-3:对比缺陷修复前后两个版本程序相应的抽象语法树;
[0028] 步骤3)-4:提取缺陷版本程序源代码对应的抽象语法树中发生变更的函数结点和未发生变更的函数结点;
[0029] 步骤3)-5:根据已获取的缺陷错误类型,对发生变更的函数结点标记引发该类型的缺陷错误,对未发生变更的函数结点标记不引发缺陷错误。
[0030] 步骤3)-6:函数结点信息采集完毕。
[0031] 进一步,其中上述步骤4)的具体步骤如下:
[0032] 步骤4)-1:起始状态;
[0033] 步骤4)-2:提取函数结点内的赋值结点,记录所有参与赋值操作的变量名称;
[0034] 步骤4)-3:计算参与赋值操作的变量在函数结点内出现的类型种类数;
[0035] 步骤4)-4:计算赋值语句的长度以及位于赋值符左侧的各变量名的长度;
[0036] 步骤4)-5:计算位于赋值符右侧的各变量上执行的操作个数,并记录变量在使用前是否被执行类型检查;
[0037] 步骤4)-6:根据赋值结点的上下文信息,生成缺陷代码的特征向量;
[0038] 步骤4)-6:缺陷代码特征向量生成完毕。
[0039] 进一步,其中上述步骤5)的具体步骤如下:
[0040] 步骤5)-1:起始状态;
[0041] 步骤5)-2:读取已经分好缺陷错误类型的特征向量,生成训练数据集;
[0042] 步骤5)-3:训练多分类的Logistic回归模型;
[0043] 步骤5)-4:多分类模型生成完毕。
[0044] 进一步,其中上述步骤6)的具体步骤如下:
[0045] 步骤6)-1:起始状态;
[0046] 步骤6)-2:将新的Python软件程序应用于训练完毕的多分类Logistic回归模型;
[0047] 步骤6)-3:提示开发者在测试程序中可能引发缺陷的函数,以及可能导致的缺陷错误类型。
[0048] 步骤6)-4:缺陷信息提示完毕。

附图说明

[0049] 图1为本发明实施例的一种基于抽象语法树的Python类型缺陷检测方法的流程图。
[0050] 图2为图1中收集软件缺陷报告信息的流程图。
[0051] 图3为图1中收集软件缺陷源代码信息的流程图。
[0052] 图4为图1中生成缺陷修复前后两个版本源代码的抽象语法树,收集变更函数结点信息的流程图。
[0053] 图5为图1中收集缺陷代码特征向量信息的流程图。
[0054] 图6为图1中使用缺陷代码特征向量训练多分类模型的流程图。
[0055] 图7为图1中缺陷信息反馈的流程图。

具体实施方式

[0056] 为了更好地说明本发明的技术内容,特结合所附图式作如下说明。
[0057] 图1为本发明实施例的一种基于抽象语法树的Python类型缺陷检测方法的流程图。本发明提出的一种基于抽象语法树的Python类型缺陷检测方法,其特征在于,包括下列6个步骤:
[0058] 步骤1:收集Python软件缺陷报告信息,提取缺陷错误类型。从软件缺陷追踪系统中收集Python软件中已被修复的缺陷报告信息,包括缺陷标识符、摘要和描述。判断以下9种Python内置异常类型是否在摘要和描述中出现:ArithmeticError,AttributeError,KeyError,IndexError,IOError,NameError,SyntaxError,TypeError,ValueError。将其中出现的错误类型加入缺陷错误类型列表error_list中。
[0059] 步骤2:获取缺陷修复前后两个版本程序的源代码。根据步骤1中获取的缺陷标识符,从软件版本控制系统的提交记录中找出修改的文件名和对应的修复版本号,然后根据文件名和版本号从软件版本控制系统(如CVS)中下载缺陷修复前后两个版本的源代码。
[0060] 步骤3:生成两个版本源代码对应的抽象语法树,匹配获取变更函数定义结点和未变更函数定义结点并分别标记错误类型。对步骤2中获取的包含缺陷的源代码和修复后的源代码进行词法分析和语法分析,利用Python标准库中的ast模块生成抽象语法树。为了更好地对变更结点进行分类,我们根据Python标准库中定义的抽象语法,为抽象语法树中的每个结点设置label和value,同时设置结点标识符。对于每个实体结点x,l(x)为结点的label,即结点的类型,如函数定义;v(x)为结点的value,表示结点的内容,中间结点的value依赖于其label,如if控制语句的value为其对应的条件表达式,叶子结点的value为语句的文本表示,如函数调用语句等;结点标识符id用于唯一标识结点。
[0061] 后序遍历两个版本的抽象语法树,依次匹配各个对应结点,寻找缺陷版本源代码对应的抽象语法树中发生变更的且结点类型为函数定义(FunctionDef)的结点以及未发生变更且结点类型为函数定义的结点,分别用元组δ1=(结点标识符,error_list)和元组δ2=(结点标识符,0)表示,其中,δ1中的error_list为步骤1中获取的缺陷错误类型列表,δ2中的0表示相应的函数定义结点不引发缺陷。对于未发生变更的函数结点,设其引发错误类型为NoError,则δ1和δ2可用统一的形式表示:
[0062] δk=(结点标识符,error_listk)
[0063] 其中,error_list的取值种类为10,分别为ArithmeticError,AttributeError,KeyError,IndexError,IOError,NameError,SyntaxError,TypeError,ValueError以及NoError。
[0064] 步骤4:根据变更函数结点上下文信息,生成缺陷代码特征向量。对于每个由步骤3提取的函数定义结点func_def,使用树的中序遍历方式遍历func_def,得出func_def内所有赋值(Assign)结点,构成赋值结点列表assign_list。对于assign_list中的每个赋值结点,记录该结点中参与赋值操作的所有变量名称,如此可获得函数结点中所有参与赋值运算的变量名,构成变量名列表name_list。对于变量名列表中的每个变量名name,使用PySonar2工具统计name在函数定义结点func_def中出现过的不同类型的个数,由此可以获得函数结点func_def中所有变量名与其类型种类数的映射:
[0065] map={name1:n1,name2:n2,…,namek:nk}
[0066] 针对赋值结点列表assign_list中的每个赋值结点assign_item,取出所有位于赋值符(=)左侧的变量名,构成left_names,并取出所有位于赋值符右侧的变量名,构成right_names,然后分别计算如下5个特征值:(1)使用Python中的astunparse模块将其反向解析,得到赋值语句源代码,得出该赋值语句的长度assign_len;(2)left_names中变量名的长度最小值min_name_len;(3)根据映射关系map分别计算right_names中每个变量的类型种类数,据此得出最大的类型种类数max_category;(4)对于right_names中的变量名,分别求出直接施加在该变量上的方法调用次数,然后得出最大的方法调用次数max_call,例如,表达式x+y等价于x.add(y),即在对象x和y上的方法调用次数分别为1和0,又如在表达式x+y.z()+x.z()中,等价于x.add(y.z())+x.z(),即在对象x和y上的方法调用次数分别为2和1,两个例子中的max_call分别为1和2;(5)在抽象语法树中,找出函数定义结点func_def到赋值结点assign_item路径上的所有其余结点,判断right_names中的变量是否均被执行类型检查(即作为type或instance的操作数),得到all_checked。其中,all_checked的取值为1或0,若right_names中的所有变量都被执行过类型,则all_checked等于1,反之为0。进而,可以得到缺陷代码特征向量为:
[0067] Δij=[assign_lenij,min_name_lenij,max_categoryij,max_callij,all_checkedij]
[0068] 其中,i=1,2,...,M;j=1,2,...,N。M为抽象语法树中的函数定义结点数,N为函数结点中赋值结点的个数。
[0069] 步骤5:利用机器学习技术,在缺陷代码特征向量上训练多分类模型。读取步骤4中的缺陷代码特征向量及其对应的缺陷错误类型,生成训练集,训练多分类Logistic回归模型。多分类Logistic模型的计算方法如下:
[0070]
[0071]
[0072] 其中,k=0,1,2,...,c-1。y是因变量且有c种取值,从0到c-1。x=(x1,x2,...,xp)为自变量, 是回归系数。
[0073] 步骤6:提示开发者在测试Python程序文件中可能出现的缺陷信息。对于一个新的Python程序文件,应用于步骤5中得到的多分类Logistic回归模型,提示开发者在程序中可能引发缺陷的函数,以及可能的缺陷错误类型;
[0074] 图2为收集软件缺陷报告信息的流程图。具体步骤如下:步骤1:起始状态;步骤2:获取缺陷追踪系统中已被修复的缺陷报告;步骤3:从已被修复的缺陷报告中,提取缺陷标识符、摘要及描述等相关信息;步骤4:从摘要和描述信息中,提取已被修复的缺陷错误类型;步骤5:缺陷报告信息采集完毕。
[0075] 图3为收集软件缺陷源代码信息的流程图。具体步骤如下:步骤1:起始状态;步骤2:根据缺陷报告中提取的缺陷标识符,从软件版本控制系统中获取包含该缺陷标识符的提交记录;步骤3:根据提交版本号获取缺陷修复前后两个版本程序的源代码;步骤4:软件缺陷源代码信息采集完毕。
[0076] 图4为生成缺陷修复前后两个版本源代码的抽象语法树,收集变更函数结点信息的流程图。具体步骤如下:步骤1:起始状态;步骤2:为缺陷版本程序的源代码和修复版本程序的源代码分别生成抽象语法树;步骤3:对比缺陷修复前后两个版本程序相应的抽象语法树;步骤4:提取缺陷版本源代码对应的抽象语法树中发生变更的函数结点以及未发生变更的函数结点;步骤5:根据已获取的缺陷错误类型,对发生变更的函数结点标记引发该类型的缺陷错误,对未发生变更的函数结点标记不引发缺陷错误;步骤6:函数结点信息采集完毕。
[0077] 图5为收集缺陷代码特征向量信息的流程图。具体步骤如下:步骤1:起始状态;步骤2:提取函数结点内的赋值结点,记录所有参与赋值操作的变量名称;步骤3:计算参与赋值操作的变量在函数结点内出现的类型种类数;步骤4:计算赋值语句的长度以及赋值符左侧各变量名的长度;步骤5:计算赋值符右侧各变量上执行的操作个数,并记录变量在使用前是否被执行类型检查;步骤6:根据赋值结点的上下文信息,生成缺陷代码的特征向量;步骤7:缺陷代码特征向量生成完毕。
[0078] 图6为使用缺陷代码特征向量训练多分类模型的流程图。具体步骤如下:步骤1:起始状态;步骤2:读取已经分好缺陷错误类型的特征向量,生成训练数据集;步骤3:训练多分类的Logistic回归模型;步骤4:多分类模型生成完毕。
[0079] 图7为缺陷信息反馈的流程图。具体步骤如下:步骤1:起始状态;步骤2:将新的Python软件程序应用于训练完毕的多分类Logistic回归模型;步骤3:提示开发者程序中可能引发缺陷的函数,以及可能导致的缺陷错误类型;步骤4:缺陷信息提示完毕。
[0080] 综上所述,本发明提供了一种面向Python语言的、基于抽象语法树的类型缺陷检测方法,解决了目前存在的缺乏针对Python语言的类型缺陷分析、无法检测可能的缺陷错误类型等问题,进而指导软件质量的管理,提高软件的可维护性。