买专利,只认龙图腾
首页 专利交易 科技果 科技人才 科技服务 商标交易 会员权益 IP管家助手 需求市场 关于龙图腾
 /  免费注册
到顶部 到底部
清空 搜索

【发明授权】接口参数约束代码入口定位方法与系统_北京大学_201810737261.X 

申请/专利权人:北京大学

申请日:2018-07-06

公开(公告)日:2021-04-27

公开(公告)号:CN109062784B

主分类号:G06F11/36(20060101)

分类号:G06F11/36(20060101);G06F8/75(20180101)

优先权:

专利状态码:有效-授权

法律状态:2021.04.27#授权;2019.01.15#实质审查的生效;2018.12.21#公开

摘要:本发明公开了一种接口参数约束代码入口定位方法与系统,先收集预设的输入参数的场景下系统客户端中的代码覆盖数据,并据此对系统客户端进行选择性插桩以插入探针,然后运行插桩后的系统客户端并演示场景,以触发读取接口参数和执行探针,通过探针打印出当前的函数调用栈和输入控件元信息,并据此定位到接口参数约束代码的入口函数。本发明有效解决了现有技术在将信息系统中的数据和功能服务化的过程中,在对接口参数约束代码定位时难以定位代码入口的问题,从而帮助开发者快速定位到接口参数约束代码入口,从而帮助开发者更快筛选出真正跟参数约束密切相关的代码。

主权项:1.一种接口参数约束代码入口定位方法,其特征在于,包括:步骤A:收集预设的输入参数的场景下系统客户端中的代码覆盖数据;步骤B:基于所述代码覆盖数据对所述系统客户端进行选择性插桩,以插入探针;步骤C:运行插桩后的系统客户端,并演示所述场景,以触发读取接口参数和执行所述探针,所述探针打印出当前的函数调用栈和输入控件元信息;步骤D:根据所述函数调用栈和输入控件元信息,定位到接口参数约束代码的入口函数,包括:当未使用第三方库时,通过回溯、分析所述函数调用栈,定位接口参数约束代码的入口函数;当使用第三方框架来实现对参数的约束时,根据所述输入控件元信息与所述第三方库框架的函数绑定关系定位接口参数约束代码的入口函数。

全文数据:接口参数约束代码入口定位方法与系统技术领域本发明涉及计算机软件,尤其涉及一种接口参数约束代码入口定位方法与系统。背景技术在大数据时代,将信息系统中的数据和功能服务化,以便实现数据的开放、共享与融合,具有十分重要的意义。目前,服务化的常见形式是通过Web应用编程接口WebApplicationProgrammingInterface,WebAPI来开放系统的功能和数据。为了保证服务化后不影响原系统的正常运行,必须对API接口进行必要的参数约束。然而,大量信息系统在开发时并未考虑到服务化的需要,原系统开发者在开发接口时没有进行严格的参数约束,服务器端对参数的约束检查并不够完备,甚至服务器端完全不检查,只依赖客户端中的参数校验。为了保证服务化的正确性,有必要在WebAPI中编写处理程序,来实现客户端的参数约束。在编写处理程序时,最直接的方法是在原系统的客户端中定位到接口参数约束代码,以此作为参考。接口参数约束代码的定位过程存在着以下两个挑战:1代码入口难以定位:参数输入控件与事件处理函数之间的绑定关系较为复杂,事件处理的过程也难以跟踪与定位,这使得开发者很难定位约束代码的入口。2关键代码定位较为困难:约束代码片段中通常存在无关语句和外部函数调用,开发者很难定位到跟参数约束真正相关的关键语句。发明内容本发明主要目的在于,提供一种接口参数约束代码入口定位方法与系统,以解决现有技术在将信息系统中的数据和功能服务化的过程中,在对接口参数约束代码定位时难以定位代码入口的问题。本发明是通过如下技术方案实现的:一种接口参数约束代码入口定位方法,包括:步骤A:收集预设的输入参数的场景下系统客户端中的代码覆盖数据;步骤B:基于所述代码覆盖数据对所述系统客户端进行选择性插桩,以插入探针;步骤C:运行插桩后的系统客户端,并演示所述场景,以触发读取接口参数和执行所述探针,所述探针打印出当前的函数调用栈和输入控件元信息;步骤D:根据所述函数调用栈和输入控件元信息,定位到接口参数约束代码的入口函数。进一步地,所述步骤A包括:步骤A1:获取系统初始化后不演示所述场景时的代码覆盖数据C1和演示所述场景时的代码覆盖数据C2;步骤A2:计算C1与C2的差值,并将C1与C2的差值作为所述代码覆盖数据。进一步地,所述步骤B中,所述选择性插桩的范围限于所述场景下执行过的代码,且插桩的位置限于有可能读取接口参数的程序操作点。进一步地,所述函数调用栈包括位于底层的系统库函数、位于所述系统库函数之上的事件回调函数、位于所述事件回调函数之上的参数约束入口函数;所述输入控件元信息包括事件监听函数、控件本身属性。进一步地,所述步骤C中,在演示所述场景之前设定关键字,当读取到包含所述关键字的接口参数时,所述探针打印出当前的函数调用栈和输入控件元信息。一种接口参数约束代码入口定位系统,包括:代码覆盖数据收集模块,用于收集预设的输入参数的场景下系统客户端中的代码覆盖数据;插桩模块,用于基于所述代码覆盖数据对所述系统客户端进行选择性插桩,以插入探针;在运行插桩后的系统客户端并演示所述场景时,触发读取接口参数和执行所述探针,所述探针打印出当前的函数调用栈和输入控件元信息;接口参数约束代码入口函数定位模块,用于根据所述函数调用栈和输入控件元信息,定位到接口参数约束代码的入口函数。进一步地,所述代码覆盖数据收集模块具体用于:获取系统初始化后不演示所述场景时的代码覆盖数据C1和演示所述场景时的代码覆盖数据C2;以及计算C1与C2的差值,并将C1与C2的差值作为所述代码覆盖数据。进一步地,所述选择性插桩的范围限于所述场景下执行过的代码,且插桩的位置限于有可能读取接口参数的程序操作点。进一步地,所述函数调用栈包括位于底层的系统库函数、位于所述系统库函数之上的事件回调函数、位于所述事件回调函数之上的参数约束入口函数;所述输入控件元信息包括事件监听函数、控件本身属性。进一步地,当读取到包含预设关键字的接口参数时,所述探针打印出当前的函数调用栈和输入控件元信息。与现有技术相比,本发明提供的接口参数约束代码入口定位方法,先收集预设的输入参数的场景下系统客户端中的代码覆盖数据,并据此对系统客户端进行选择性插桩以插入探针,然后运行插桩后的系统客户端并演示场景,以触发读取接口参数和执行探针,通过探针打印出当前的函数调用栈和输入控件元信息,并据此定位到接口参数约束代码的入口函数。本发明有效解决了现有技术在将信息系统中的数据和功能服务化的过程中,在对接口参数约束代码定位时难以定位代码入口的问题,从而帮助开发者快速定位到接口参数约束代码入口,从而帮助开发者更快筛选出真正跟参数约束密切相关的代码。附图说明图1是本发明提供的接口参数约束代码定位方法的总体流程;图2是函数内参数影响数据流方程的求解示例;图3是关键代码分析工具的整体框架示意图;图4是控制流图示例;图5是本发明提供的接口参数约束代码定位方法的具体流程示意图;图6是本发明提供的接口参数约束代码定位系统的组成示意图。具体实施方式为使本发明的目的、技术方案和优点更加清楚明白,下面结合实施例和附图,对本发明作进一步详细说明。术语解释:服务化:将信息系统中的数据与功能以服务的形式提供出来。WebAPI:由信息系统提供的网络访问接口,通常基于HTTP协议,并通过JSON或XML格式传输数据。接口参数:信息系统中客户端通过WebAPI与服务器端进行通信时提供的参数。参数约束:信息系统对接口参数所允许的值的限制,可分为类型约束和值域约束。约束代码入口:信息系统客户端代码中,对参数进行约束检查的入口函数约束关键代码:信息系统客户端代码中,排除无关的变量、语句后,与参数约束真正相关的代码。本发明提供的接口参数约束代码定位方法主要包括两个阶段:约束代码入口定位阶段和关键代码定位阶段。其中,约束代码入口定位阶段的目标是辅助开发者高效、快速地从客户端繁杂的代码中定位到所需参数约束代码的入口,以此作为整个代码定位过程的起点。关键代码定位阶段的目标是辅助开发者进一步地理解、定位原系统客户端中对参数进行约束的关键代码。本发明提供的接口参数约束代码定位方法的总体流程如图1所示,各步骤说明如下:步骤1.预设一个输入参数的场景对接口参数的约束可视为系统客户端中的一个功能,对此功能进行代码定位时,需要根据实际需要设计一个场景。以大多数系统都有的账号注册功能为例,在用户进行注册时,需要填写各种信息,如账号、密码等等,如果想要定位到对这些参数进行约束的代码片段,则需要设计一个输入账号注册信息的场景。为了尽可能地覆盖更多的程序分支,设计的场景应尽量触发多个参数约束条件。步骤2.收集场景下系统客户端的代码覆盖数据在场景下,接口参数的约束代码将会得到执行,这部分代码是开发者真正需要关注的部分。通过代码覆盖率测试工具可以分析得到在场景下所有执行过的代码。而系统客户端中其他部分的代码,如在场景之前执行的初始化代码、在场景下未执行的其他功能的代码,将不会被记录到。步骤3.对原系统客户端进行插桩后再次演示场景基于步骤2中收集到的代码覆盖数据,可以对原系统客户端进行选择性插桩:插桩范围限于场景下执行过的代码,并且插桩的位置限于有可能读取参数的程序操作点。插桩完成后,需要运行插桩后的系统客户端,并再次演示场景。步骤4.定位接口参数约束代码入口函数再次演示场景时,接口参数的约束代码会再次被触发。此时,由于已经对读取参数的程序操作点进行插桩,插桩探针也会随之被触发,而探针的主要作用在于打印出当前的函数调用栈以及相关输入控件的元信息。通过查询函数调用栈和输入控件的元信息,可以定位到约束代码的入口函数。为了定位过程更加方便,可根据实际的参数输入进行插桩信息的过滤。步骤5.收集场景下从入口函数开始的函数调用关系在场景中检查参数约束时,从约束代码的入口函数开始,有可能会涉及到若干其他函数的调用。例如,原系统的开发者可能会调用一些第三方库来对参数进行计算、转换等操作;此外,为了实现更好的代码结构,原系统开发者可能将不同的子约束抽取为独立函数,再通过函数调用的方式来进行参数约束的检查。为了进行更全面的约束代码定位,有必要收集场景下从入口函数开始的函数调用关系。考虑到不同语言平台可能会有多态、函数式编程等特性,只靠静态分析难以得出函数调用的真实情况,因此有必要使用程序插桩的方式来收集这部分信息。此时,程序插桩的代码范围同样限于场景下执行过的代码,但插桩的位置变成了函数调用的程序操作点。此步骤收集的函数调用信息将导出到数据库或文件中,以便后续步骤使用。步骤6.选择一个函数进行分析启动基于Web的关键代码分析工具的服务器端,并通过浏览器访问关键代码分析工具的前端页面。服务器读取原系统客户端的代码以及步骤5中收集的函数调用关系数据,返回给前端页面,前端页面以可视化的界面展示源代码。前端提供了基于函数调用关系和基于文本搜索的两种跳转方式,可以利用这两种方式在函数之间跳转浏览。在聚焦到某个特定函数时,可以输入一个变量名,关键代码分析工具根据静态数据流分析方法,计算出该变量在此函数中可能影响的语句并高亮显示。仅需关注高亮后的代码,特别是里面涉及到的分支语句,即可快速地定位到跟参数约束有关的关键语句。7.判定是否找到所有约束代码步骤6中主要讨论了一个函数内的代码定位情况,如果原系统中参数的约束涉及到多个函数,则需要重复步骤6,在不同函数中定位到各自的关键语句,从而得到尽可能完备的约束代码。上述各步骤中,步骤1是准备阶段,步骤2、3、4是约束代码入口定位阶段,步骤5、6、7是关键代码定位阶段。根据接口参数约束代码定位方法的总体流程,提出了本发明实施例的接口参数约束代码定位方法的具体步骤,如图5所示,该定位方法包括:步骤A:收集预设的输入参数的场景下系统客户端中的代码覆盖数据;步骤B:基于代码覆盖数据对系统客户端进行选择性插桩,以插入探针;步骤C:运行插桩后的系统客户端,并演示场景,以触发读取接口参数和执行探针,探针打印出当前的函数调用栈和输入控件元信息;步骤D:根据函数调用栈和输入控件元信息,定位到接口参数约束代码的入口函数;步骤E:通过程序插桩的方式,采集场景下从入口函数开始的函数调用关系;步骤F:读取系统客户端的代码以及函数调用关系,并据此在函数之间跳转浏览,对各函数进行关键代码分析,以定位出与接口参数相关的所有约束代码。接口参数约束代码定位方法实质包括了接口参数约束代码入口定位方法和关键代码定位方法两部分。上述各步骤中,步骤A、步骤B、步骤C和步骤D共同组成接口参数约束代码入口定位方法,步骤E和步骤F共同组成关键代码定位方法。下面对各步骤进行详细说明。准备阶段:该阶段主要是需要预先设定一个输入参数的场景,设定好输入参数的场景后,就进入约束代码入口定位阶段。约束代码入口定位阶段:步骤A:收集预设的输入参数的场景下系统客户端中的代码覆盖数据。为了减少程序插桩的开销,最好只对场景下执行过的代码进行插桩,这一目标可以通过收集场景下的代码覆盖数据来实现。可通过代码覆盖率测试工具来收集场景下的代码覆盖数据。目前,大部分代码覆盖率测试工具的使用过程是,先使用插桩工具对代码进行插桩,然后演示功能场景或者自动运行测试脚本,得出该场景下的代码覆盖数据,最终的数据通常以某个函数或某条语句执行总次数的形式进行展示。这种方式收集的数据包含了系统初始化及目标功能场景中所有的代码覆盖数据,而通常情况下,单一功能中执行过的代码量会大大少于整个系统初始化的代码量。因此,为了更精确地得到场景下执行过的代码数据,步骤A包括:步骤A1:获取系统初始化后不演示场景时的代码覆盖数据C1和演示场景时的代码覆盖数据C2;步骤A2:计算C1与C2的差值,并将C1与C2的差值作为代码覆盖数据。即收集两份代码覆盖数据,一份是系统初始化后不演示场景的数据C1,另一份是系统初始化后直接演示场景的数据C2,然后对这两份数据求差集,结果即为仅在场景下执行过的代码数据。一些代码覆盖率测试工具支持实时统计,只需在系统初始化完成后开启测试工具,然后演示场景,演示完成后停止测试工具,此时测试工具收集到的即为场景下的代码覆盖数据。步骤B:基于代码覆盖数据对系统客户端进行选择性插桩,以插入探针。该步骤主要需要注意的是插桩范围与插桩点的选择,该步骤的选择性插桩范围限于场景下执行过的代码,并且插桩的位置限于有可能读取接口参数的程序操作点。步骤C:运行插桩后的系统客户端,并演示场景,以触发读取接口参数和执行探针,探针打印出当前的函数调用栈和输入控件元信息。无论是哪种架构的系统,通常都是通过输入控件来获取用户的输入参数的,而对参数进行约束检查时的第一步往往是从输入控件中读取参数。因此,通过对“从输入控件中读取参数”这一程序操作点进行插桩,当插桩探针被触发时,便可有效地收集到与参数约束相关的运行时信息,并确定对应的输入控件,最终以函数调用栈和输入控件元信息的形式进行展现。表1、表2、表3分别给出了AS系统、BS系统、CS系统中各自的一些插桩点设计实例。表1展示了安卓系统中的常用输入控件和相关信息。在安卓系统中,参数的获取方式是通过调用特定对象的方法来实现的,因此,对安卓系统的插桩点是方法调用这一程序操作点。为了避免多余的开销,只有在调用对象和调用方法都匹配的情况下,才会打印方法调用栈和控件元信息。表1:AS系统中插桩点设计实例以安卓系统为例表2展示了BS系统中的常用输入控件和相关信息。在BS系统中,参数的获取方式是通过访问HTML元素的属性来实现的,因此,对BS的插桩点是获取对象属性这一程序操作点。为了避免多余的开销,只有在获取属性时的对象和获取的属性名都匹配的情况下,才会打印方法调用栈和控件元信息。表2:BS系统中插桩点设计实例表3展示了C#客户端中的一些输入控件和相关信息。在C#客户端中,参数的获取方式是通过访问输入控件的特定属性来实现的,因此,对C#的插桩点是获取对象属性这一程序操作点。为了避免多余的开销,只有在获取属性时的对象和获取的属性名都匹配的情况下,才会打印方法调用栈和控件元信息。表3:CS系统中插桩点设计实例以C#客户端为例步骤D:根据函数调用栈和输入控件元信息,定位到接口参数约束代码的入口函数。在对约束代码的入口进行定位时,本发明使用了两种类型的信息,一类是函数调用栈信息,另一类是输入控件的元信息。基于这两类信息的入口定位方法如下:1、基于函数调用栈的入口定位:在未使用第三方库的情况下,原系统开发者在对输入参数进行约束检查时,会先显式地从输入控件中读取参数。此时插桩探针被触发,打印出的函数调用栈结构如表4所示。表4第三方库函数可选应用层函数可选参数约束入口函数事件回调函数系统库函数n……系统库函数1在栈的最底层,通常是一些系统库函数,如用于实现事件循环、消息机制的函数。系统库函数之上是事件回调函数,如点击事件、内容改变事件、失去焦点事件等事件的回调函数。事件回调函数之上是参数约束入口函数,有些时候事件回调函数和参数约束入口函数实际是同一个函数。在入口函数之上,可能还有应用层函数和第三方库函数,应用层函数是指原系统开发者自行编写的函数,第三方库函数可能是获取参数及进行相关处理如加密、转换等操作的函数。无论是否存在这两类函数,在入口函数及其之上的调用栈,至少有一个函数会触发读取参数的操作。此时,插桩后的探针被触发,打印出运行时的函数调用栈。通过回溯、分析调用栈,便能定位到具体的入口函数。2、基于控件元信息的入口定位:在使用第三方框架来实现对参数的约束时,读取参数的操作通常由框架发起,读取完毕后框架负责将参数的值传递到开发者定义的参数约束入口函数中。此时的函数调用栈与表4中类似,但缺少了最重要的入口函数,因此无法通过函数调用栈来定位约束入口。为了应对这种情况,本发明采用了打印控件元信息的方式进行辅助定位。在读取参数探针被触发时,打印参数所属输入控件元信息,输入控件元信息包括绑定的事件监听函数、控件本身属性等等。由于第三方库框架通常使用这些元信息进行函数绑定,因此开发者可以通过这些元信息定位到约束代码的入口函数。需要注意的是,如果仅依靠上一小节中表1、表2、表3的条件来打印信息,可能会出现一些冗余。以BS系统为例,假设HTML网页中一个表单有多个文本输入框,在表单填写完成时,各个输入框的约束检查相继被触发,此时不同输入框的信息会一并打印,而开发人员可能只关注其中一个输入框的约束条件。为了减少冗余信息,可在演示场景之前设定关键字,只有当读取到包含设定的关键字的接口参数时,探针打印出当前的函数调用栈和输入控件元信息。定位约束代码入口函数后,就进入关键代码定位阶段。关键代码定位阶段仍需要再次执行一次场景,以便收集运行时的函数调用关系。关键代码定位阶段:步骤E:通过程序插桩的方式,采集场景下从入口函数开始的函数调用关系。为收集真实的函数调用信息,此阶段仍进行程序插桩,插桩的代码范围限于场景下执行过的代码,但插桩的位置变成了函数调用的程序操作点。在每次函数调用发生时,收集的信息如表5所示。表5:信息类型说明caller函数调用方,包含函数名和函数位置信息callee函数被调用方,包含函数名和函数位置信息callSite在caller中发生此次函数调用的位置考虑到开发人员只关心从入口函数开始的函数调用关系,最终呈现给开发者的也应只有这部分数据。为实现这一结果,有两种途径:1、先收集全量函数调用信息,之后再进行筛选;2、在收集信息的过程中就只收集从入口函数开始的函数调用关系。由于第一种途径不仅会大大增加插桩后程序的运行开销,还会引入额外的筛选过程,因此本文采用了第二种途径。不同信息系统的客户端使用的编程语言各种各样,采用的内存模型也有所不同。从总体来看,它们使用的内存模型可以分为两大类:单线程模型SingleThreadingModel和多线程模型MultithreadingModel。对于这两种模型,收集函数调用信息时需要考虑的问题也有所不同,具体如下:单线程模型:单线程模型的一个代表是BS系统中的JavaScript。JavaScript采用了基于事件循环EventLoop的单线程模型,同一时间只能执行一个函数。在执行函数的过程中,如果遇到异步方法,会在执行完后立即返回,如果遇到同步方法,则会执行完后再返回。异步方法中的操作会在事件队列中添加一个事件,当JavaScript运行时执行完当前函数、函数调用栈为空的时候,JavaScript运行时就会从事件队列中取出一个事件并执行其回调函数。对于以JavaScript为代表的单线程模型客户端来说,只需要采集单个线程内的函数调用关系。多线程模型:多线程模型是客户端系统中更常见的模型,CC++JavaC#等语言都采用了多线程的内存模型。尽管如此,在大多数客户端的实现中,跟UI相关的操作都是在主线程MainThread中进行的,触发事件回调、调用入口函数的线程也正是主线程。虽然在入口函数的运行过程中,可能存在着调用其他线程的方法来进行参数约束检查的情况例如动态请求服务器判定参数是否合法,但通常也会采用同步等待的方式来获取结果。因此,采集主线程上从入口函数开始的函数调用关系是可行的。综上,无论是多线程模型还是单线程模型,只考虑单个线程内的函数调用情况是合理的。收集完从入口函数开始的所有函数调用关系信息后,插桩工具以文件或数据库的形式将这些信息保存下来。在关键代码分析工具中点击一个函数调用点CallSite时,分析工具可以根据保存的信息查找到其实际调用的函数,进而在前端页面中进行展示。步骤F:读取系统客户端的代码以及函数调用关系,并据此在函数之间跳转浏览,对各函数进行关键代码分析,以定位出与接口参数相关的所有约束代码。该步骤主要包括计算函数内变量影响的数据流分析和关键代码分析。1、计算函数内变量影响的数据流分析:通过关键代码分析工具跳转到特定函数后,可以输入一个函数内的变量名,然后观察这个变量在函数内可能影响的语句。先考虑一个简单的情形:开发者关注的变量正好是该函数的参数。为便于后文描述,假定用户最开始指定的变量为x,那么〖In〗_b是指在进入一个基本块b之前跟x有关的变量的集合,特别地,〖In〗_initial是函数内第一个基本块的In集合;〖Out〗_b是指在经过一个基本块b之后跟x有关的变量的集合;〖Gen〗_b是指基本块内新产生的跟x有关的变量;〖Kill〗_b是指基本块内新产生的跟x无关的变量;〖Use〗_b是基本块内被使用过的变量的集合;而最终的〖Highlight〗_b则是基本块b内需要高亮的变量。由定义可知,〖Gen〗_b实际上是基本块内最后一次赋值跟x有关的变量v的集合,与之相反,〖Kill〗_b实际上是基本块内最后一次赋值跟x无关的变量v的集合。根据〖Gen〗_b和〖Kill〗_b,再结合〖In〗_b,可以计算得到每个基本块的〖Out〗_b。这实际上是一个前向数据流分析的问题,每个块中数据流信息的计算依赖于它前面的基本块。求解算法的基本思想是不停地迭代计算每个基本块的In集合与Out集合,直到所有基本块的Out集合不再发生改变为止。图2是采用上述算法求解出来的一个简单示例。假设选择了参数x,那么Entry的Out集合即为{x}。由于Entry是s1的唯一前驱结点,因此s1的In集合就等于〖Out〗_entry。在s1中,对a进行了赋值,且该赋值语句跟x有关,所以s1的Gen集合为{a},Kill集合为空集,由此计算出Out集合为{a,x}。s2也是一条赋值语句,但b的赋值与x无关,因此b被Kill掉,s2的Out集合仍然是{a,x}。s3不是赋值语句,Gen集合与Kill集合均为空集,{a,x}被原样传递给后续结点。最后是s4和s5,它们都对b进行了赋值,但s4中的赋值与x有关因为a已经被x影响了,s5中的赋值与x无关因为b未被x影响,因此,这两条语句最终计算的Out集合并不相同。上述算法考虑的是指定的变量正好是函数参数的情况。在实际场景中,往往也需要考虑另一种情况,即开发者关心的变量并不是函数自身的参数。例如,对接口参数进行约束检查的某个函数F并不接收任何参数,而是在进入函数体后通过某种方式读取到了用户输入的参数,并保存在一个变量x中,之后再针对该变量进行约束检查。此时开发者关心的是变量x在函数体内会影响哪些语句,而x本身并不是函数F的参数。这种情况下的数据流方程及其求解算法跟前述方法大同小异,关键的不同之处在于,此时需要记录函数内各条语句是否为对x的第一次赋值。如果某条语句s是对x的第一次赋值,那么无论赋值语句的右值是否与x有关,x都应该被算入s的Gen集而不是Kill集。例如,假设函数F的第一条语句就是x=1,如果x是F的参数,则这条语句会杀死变量x,因为x被赋值过后已经跟它的原始值无关;而如果x不是F的参数,那么x则会被算入这条语句的Gen集里,最终算出的Out集也会包含x。求解完数据流方程后,可以算出每个基本块的In集合,然后将基本块内使用过的变量与In集合取交集,得到的便是该基本块内被变量x所影响的变量。将这些变量相关的语句高亮,便可帮助开发者更好地理解跟x有关的语句。当选择的x就是接口的某个参数时,此时高亮显示的正是对这个参数进行约束检查的关键代码。2、关键代码分析:本发明利用关键代码分析工具进行关键代码分析。关键代码分析工具的作用是提供给开发者一个友好的代码浏览环境,便于在函数之间跳转以及分析单个函数,它的整体框架如图3所示。关键代码分析工具基于Web实现,主要分为前端Frontend和后端Backend两部分。后端包含有数据服务器、数据读取模块和数据流分析模块。其中,数据服务器用于接收前端发送过来的HTTP请求并返回结果,数据读取模块用于读取本地文件,数据流分析模块用于进行数据流分析。前端包括导航栏、文本搜索模块、变量输入框、代码查看器和函数查看器等模块。其中,导航栏用于展示函数的浏览历史,文本搜索模块用于进行文本搜索,变量输入框用于接收输入的变量,代码查看器用于浏览系统客户端的代码,函数查看器用于展示被选中的单个函数。此外,关键代码分析工具还需要有原系统客户端的源代码以及之前步骤中收集到的函数调用记录。关键代码分析工具的前端Web页面上方是导航栏,用于展示函数的浏览历史。页面右上方有两个文本输入框和两个按钮,分别用来触发文本搜索功能和数据流分析功能。页面下半部分被分为两个面板,面板的尺寸可以通过拖动面板之间的分隔条来调整。其中,左侧面板是代码查看器,用于展示原系统客户端中单个文件的源代码;右侧面板是函数查看器,用于展示左侧面板中被选中的单个函数。代码查看器和函数查看器都支持语法高亮和代码段高亮的功能。通过代码查看器可浏览原系统客户端的代码,当点击含有目标函数信息的函数调用点时,可以跳转到对应的函数,并自动更新导航栏。此外,还可以通过文本搜索的方式搜索、定位到任意一个函数。当聚焦到某个特定函数时,函数查看器中的代码也会随之更新,此时可以在变量输入框中输入一个变量名,相关数据会被传到后端,后端进行数据流分析后,通知前端的函数查看器将该变量可能影响的语句高亮。值得一提的是,根据平台的不同,数据流分析模块也可以放在前端。例如,BS系统中需要对JavaScript进行数据流分析,此过程既可以在后端中使用Java等语言进行,也可以在前端中使用JavaScript语言来进行。本文方法的整体流程中,使用到了三种工具:代码覆盖数据收集工具、程序选择性插桩工具和关键代码分析工具。本小节将面向BS系统,给出本文定位方法所需工具的设计实例,包括JavaScript代码覆盖数据收集工具、JavaScript选择性插桩工具、JavaScrip关键代码分析工具的设计。1、JavaScript代码覆盖数据收集工具的设计:本文设计的JavaScript代码覆盖数据收集工具——JS-Coverage,是一个通过Chrome开发者工具协议ChromeDevToolsProtocol来收集代码覆盖信息的Chrome扩展程序ChromeExtensions。Chrome浏览器是一款由Google公司开发的网页浏览器,它具有简洁、快速的特点,并且提供了浏览器扩展框架,开发者可以基于Chrome的API开发出各种各样的扩展程序,为浏览器添加额外的功能。Chrome还提供了强大的开发者控制台ChromeDevTools,它通过Chrome开发者工具协议与Chrome内核进行通信,以实现对浏览器的操作、检查、DEBUG、分析等功能。在Chrome扩展程序中,同样可以通过Chrome开发者工具协议来实现一些高级的功能,例如本文提到的代码覆盖数据的收集功能。JS-Coverage的整体架构:在Chrome浏览器右上角有一JC字样按钮,点击后会弹出工具菜单,菜单使用一个HTML页面popup.html来实现,包含三个按钮:Connect、Start和Stop,这三个按钮用于向扩展程序的后台background.js发送消息。后台收到消息后,通过Chrome扩展程序的API控制浏览器中的当前页面,并收集页面中JavaScript的代码覆盖信息,最后导出成一份JSON格式的文本文件供后续流程使用。整个过程使用了部分Chrome开发者协议中的API。需要指出的是,Profiler.takePreciseCoverage方法会在获取完代码的调用次数信息后将其重置,因此,它实际返回的是两次takePreciseCoverage方法调用之间客户端JavaScript代码被调用的计数数据。开发者使用JS-Coverage扩展程序的过程如下:1使用Chrome浏览器访问目标信息系统,进入参数输入页面,点击Connect按钮,此时页面会自动重新载入;2点击Start按钮,开始演示场景;3演示场景时,输入想要检查的参数,触发相关JavaScript代码;4点击Stop按钮,停止演示场景,将场景中的代码覆盖数据保存为JSON文件。整个JSON文件对应一个JSONObject,Object中的key为JavaScript文件的URL,value是对应的代码覆盖率信息,它以数组的形式表示。数组中的元素是包含有end属性和count属性可选的Object,end代表在源文件中的字符偏移量CharacterOffset,count属性用于计算代码被调用的次数。具体来说,假设数组名为array,数组中第i个元素为array[i],则源文件中字符偏移量在array[i].end和array[i+1].end之间的代码被执行的次数为array[i+1].count次。2、JavaScript选择性插桩工具的设计:JavaScript选择性插桩工具可以通过浏览器代理的方式,基于代码覆盖数据对BS系统中的JavaScript代码进行选择性插桩,插桩的选择性体现在插桩代码范围和程序插桩点两个方面。JavaScript选择性插桩工具的工作过程,具体如下:1浏览器将HTTP请求转发给代理软件mitmproxy;2mitmproxy从原系统中请求对应资源,如果资源是JavaScript文件或HTML文档,会在下载完成后交由扩展后的Jalangi2插桩框架进行处理;3扩展后的Jalangi2基于收集到的代码覆盖数据,对JavaScript代码进行选择性插桩;4mitmproxy将插桩后的HTML、JavaScript文件返回给Web浏览器,其他类型的资源不进行插桩,直接返回。Jalangi2的插桩模块Instrumentor的工作过程是,先解析出JavaScript代码的抽象语法树AST,然后根据一系列规则进行转换,最后将转换过后的AST生成为新的JavaScript代码。插桩模块再配合上mitmproxy这样的代理工具,可以将网页中的JavaScript代码实时地进行插桩,由此便可实现对BS系统的动态分析。客户端中的代码插桩范围应限于场景下执行过的代码,为了达到此目的,需对Jalangi2的插桩模块进行扩展。扩展的整体思路是,在转换AST时,先判断该AST对应的源码是否在场景中被执行过。具体而言,Jalangi2使用了acorn库来解析JavaScript代码,在解析完成后的每个AST结点中,均有start和end两个属性,分别以字符偏移量的形式表示该结点对应代码在源代码文件中的开始和结束的位置。而最后导出的JSON文件在记录代码覆盖数据时,也同样采用了字符偏移量的形式。通过字符偏移量区间的比较,便可确定是否应该对一个AST结点进行插桩。因此,扩展后的Jalangi2插桩模块可通过JSON文件中的信息来确定具体的插桩范围,实现选择性的代码插桩。接下来考虑插桩点的问题。JavaScript和HTML文件被Jalangi2的插桩模块插桩过后,会被改写为具有插桩探针但功能不变的代码,探针结合Jalangi2的运行时环境便可一边执行一边记录原代码执行过程中的动态信息。Jalangi2提供的插桩探针的形式是JavaScript回调函数,函数的iid参数用于标记每个程序操作点的位置。当对应的操作发生时,Jalangi2运行时环境会将相关的参数准备好,调用开发者自己编写的分析函数,可根据需要操作、保存、分析这些数据。BS系统中读取参数的操作都是通过对DOM对象的属性读取来完成的,因此,在入口代码定位阶段,仅需使用getField探针。getField回调中的base正是被读取属性的对象,val是读取到的内容。因此,根据base可以判断当前读取操作是否在特定DOM对象上进行,根据val可以实现关键字过滤功能。而在关键代码定位阶段,需要收集函数调用的信息,此时使用的插桩探针是invokeFunPre和invokeFun。Jalangi2会将插桩之前的源代码保存在一个名为smap的数据结构中,将该数据导出后可供后续关键代码分析工具使用。3、JavaScript关键代码分析工具的设计:关键代码分析工具的整体架构已在图3中给出,在本文设计的JavaScript关键代码分析工具中,图中的源代码即为Jalangi2导出的smap文件,里面包含JavaScript脚本和HTML文档等源代码;函数调用记录即为上一小节中Jalangi2收集到的数据信息,以JSON格式的文本保存;前端和后端的大部分模块均使用开源组件。下文主要介绍JavaScript关键代码分析工具中的数据流分析模块espropagation,它与图3中的设计有所不同,该模块实际工作在前端。espropagation是一个在JavaScript语法树上进行变量影响数据流方程求解的工具。espropagation采用的是在ES5的抽象语法树上进行数据流方程求解的工作方式。在ES5的抽象语法树之上,espropagation使用开源库esgraph来构造程序的控制流图。图4是esgraph构造的控制流图的一个示例。在esgraph生成的控制流图中,每个流图结点flowNode均有astNode、prev和next三个属性。astNode是该流图结点对应的抽象语法树结点,要么是一条语句Statement,要么是一个表达式Expression;prev和next都是流图结点的数组,分别保存前驱结点和后继结点。构造完控制流图之后,espropagation求解函数内变量影响的数据流方程。求解过程的关键在于计算一个基本块或一条语句的Gen集和Kill集,而Gen集、Kill集是根据一个变量的值是否跟In集有关来计算的。为了判断一个变量的赋值或初始化声明是否与In集有关,需计算出该条语句中的右值是否使用到了In集中的变量,因此,首先需计算出该条语句的Use集。假设待计算Use集的结点为astNode,则在不同类型的抽象语法树结点上计算Use集的方法如表6所示:表6:ES5抽象语法树结点的Use集计算方法示例计算完赋值语句变量初始化语句的Use集之后,与该语句的In集取交集,如果结果是空集,说明该条语句中的左值与In集无关,被赋值的变量应纳入到Kill集中;反之,如果结果不是空集,说明该条语句中的左值与In集有关,被赋值的变量应纳入到Gen集中。以上考虑的是开发者指定的变量正好为函数参数时的情况,当开发者指定的变量不是函数参数时,对Gen集和Kill集的构造有所不同。espropagation工具通过迭代式算法,求解出每个语法树结点的最终状态,并将每个结点的In集、Out集、Gen集、Kill集等信息绑定到对应结点上,最后,再将每个语法树结点的In集和Use集取交集,如果不为空集,则说明该语句会被开发者指定的变量所影响,当开发者指定的变量就是原系统的参数时,此条语句就是对该参数进行约束检查的关键代码之一。基于上述接口参数约束代码定位方法,本发明另一实施例还提供了一种接口参数约束代码定位系统,如图6所示,该定位系统包括:代码覆盖数据收集模块1,用于收集预设的输入参数的场景下系统客户端中的代码覆盖数据;插桩模块2,用于基于代码覆盖数据对系统客户端进行选择性插桩,以插入探针;在运行插桩后的系统客户端并演示场景时,触发读取接口参数和执行探针,探针打印出当前的函数调用栈和输入控件元信息;接口参数约束代码入口函数定位模块3,用于根据函数调用栈和输入控件元信息,定位到接口参数约束代码的入口函数;插桩模块2还用于通过程序插桩的方式,采集场景下从入口函数开始的函数调用关系;定位系统还包括:关键代码分析模块4,用于读取系统客户端的代码以及函数调用关系,并据此在函数之间跳转浏览,对各函数进行关键代码分析,以定位出与接口参数相关的所有约束代码。该定位系统实质包括接口参数约束代码入口定位系统和关键代码定位系统两部分。上述各模块中,代码覆盖数据收集模块1、插桩模块2和接口参数约束代码入口函数定位模块3共同组成接口参数约束代码入口定位系统,由插桩模块2和关键代码分析模块4共同组成关键代码定位系统。需指出的是,插桩模块2在接口参数约束代码入口定位系统中执行动作与在关键代码定位系统中执行的动作是有所区别的。插桩模块2在接口参数约束代码入口定位系统中执行动作是,基于代码覆盖数据对系统客户端进行选择性插桩,以插入探针;在运行插桩后的系统客户端并演示场景时,触发读取接口参数和执行探针,探针打印出当前的函数调用栈和输入控件元信息。插桩模块2在关键代码定位系统中执行的动作是,通过程序插桩的方式,采集场景下从入口函数开始的函数调用关系。代码覆盖数据收集模块1具体用于:获取系统初始化后不演示场景时的代码覆盖数据C1和演示场景时的代码覆盖数据C2;以及计算C1与C2的差值,并将C1与C2的差值作为代码覆盖数据。选择性插桩的范围限于场景下执行过的代码,且插桩的位置限于有可能读取接口参数的程序操作点。函数调用栈包括位于底层的系统库函数、位于系统库函数之上的事件回调函数、位于事件回调函数之上的参数约束入口函数;输入控件元信息包括事件监听函数、控件本身属性。当读取到包含预设关键字的接口参数时,探针打印出当前的函数调用栈和输入控件元信息。程序插桩的代码范围限于场景下执行过的代码,且插桩的位置为函数调用的程序操作点。当系统客户端为单线程模型时,插桩模块2采集单个线程内的函数调用关系,当系统客户端为多线程模型时,插桩模块2采集主线程上从入口函数开始的函数调用关系。关键代码分析模块4如图3所示,基于Web,包括前端和后端,其中:前端包括:导航栏,用于展示函数的浏览历史;文本搜索模块,用于进行文本搜索;变量输入框,用于接收输入的变量;代码查看器,用于浏览系统客户端的代码;函数查看器,用于展示被选中的单个函数;后端包括:数据服务器,用于接收前端发送过来的HTTP请求并返回结果;数据读取模块,用于读取本地文件;数据流分析模块,用于进行数据流分析。对于装置实施例而言,由于其与方法实施例基本相似,所以描述的比较简单,相关之处参见方法实施例的部分说明即可。该定位系统与上述定位方法相对应,用于执行上述定位方法。该定位系统中各模块的具体工作原理参考上述定位方法中的相应流程的说明即可。上述实施例仅为优选实施例,并不用以限制本发明的保护范围,在本发明的精神和原则之内所作的任何修改、等同替换和改进等,均应包含在本发明的保护范围之内。

权利要求:1.一种接口参数约束代码入口定位方法,其特征在于,包括:步骤A:收集预设的输入参数的场景下系统客户端中的代码覆盖数据;步骤B:基于所述代码覆盖数据对所述系统客户端进行选择性插桩,以插入探针;步骤C:运行插桩后的系统客户端,并演示所述场景,以触发读取接口参数和执行所述探针,所述探针打印出当前的函数调用栈和输入控件元信息;步骤D:根据所述函数调用栈和输入控件元信息,定位到接口参数约束代码的入口函数。2.如权利要求1所述的接口参数约束代码入口定位方法,其特征在于,所述步骤A包括:步骤A1:获取系统初始化后不演示所述场景时的代码覆盖数据C1和演示所述场景时的代码覆盖数据C2;步骤A2:计算C1与C2的差值,并将C1与C2的差值作为所述代码覆盖数据。3.如权利要求2所述的接口参数约束代码入口定位方法,其特征在于,所述步骤B中,所述选择性插桩的范围限于所述场景下执行过的代码,且插桩的位置限于有可能读取接口参数的程序操作点。4.如权利要求1所述的接口参数约束代码入口定位方法,其特征在于,所述函数调用栈包括位于底层的系统库函数、位于所述系统库函数之上的事件回调函数、位于所述事件回调函数之上的参数约束入口函数;所述输入控件元信息包括事件监听函数、控件本身属性。5.如权利要求1所述的接口参数约束代码入口定位方法,其特征在于,所述步骤C中,在演示所述场景之前设定关键字,当读取到包含所述关键字的接口参数时,所述探针打印出当前的函数调用栈和输入控件元信息。6.一种接口参数约束代码入口定位系统,其特征在于,包括:代码覆盖数据收集模块,用于收集预设的输入参数的场景下系统客户端中的代码覆盖数据;插桩模块,用于基于所述代码覆盖数据对所述系统客户端进行选择性插桩,以插入探针;在运行插桩后的系统客户端并演示所述场景时,触发读取接口参数和执行所述探针,所述探针打印出当前的函数调用栈和输入控件元信息;接口参数约束代码入口函数定位模块,用于根据所述函数调用栈和输入控件元信息,定位到接口参数约束代码的入口函数。7.如权利要求6所述的接口参数约束代码入口定位系统,其特征在于,所述代码覆盖数据收集模块具体用于:获取系统初始化后不演示所述场景时的代码覆盖数据C1和演示所述场景时的代码覆盖数据C2;以及计算C1与C2的差值,并将C1与C2的差值作为所述代码覆盖数据。8.如权利要求7所述的接口参数约束代码入口定位系统,其特征在于,所述选择性插桩的范围限于所述场景下执行过的代码,且插桩的位置限于有可能读取接口参数的程序操作点。9.如权利要求6所述的接口参数约束代码入口定位系统,其特征在于,所述函数调用栈包括位于底层的系统库函数、位于所述系统库函数之上的事件回调函数、位于所述事件回调函数之上的参数约束入口函数;所述输入控件元信息包括事件监听函数、控件本身属性。10.如权利要求6所述的接口参数约束代码入口定位系统,其特征在于,当读取到包含预设关键字的接口参数时,所述探针打印出当前的函数调用栈和输入控件元信息。

百度查询: 北京大学 接口参数约束代码入口定位方法与系统

免责声明
1、本报告根据公开、合法渠道获得相关数据和信息,力求客观、公正,但并不保证数据的最终完整性和准确性。
2、报告中的分析和结论仅反映本公司于发布本报告当日的职业理解,仅供参考使用,不能作为本公司承担任何法律责任的依据或者凭证。