一种C语言的指针类型分析方法转让专利

申请号 : CN202010842855.4

文献号 : CN112100059B

文献日 :

基本信息:

PDF:

法律信息:

相似专利:

发明人 : 杨昱天申文博周亚金任奎

申请人 : 浙江大学

摘要 :

本发明公开了一种C语言的指针类型分析方法,能快速分析大规模C代码中指针变量所有可能指向的类型。本方法先将输入程序的所有C语言源代码转换并整合为LLVM IR比特码,并根据比特码中包含的类型信息初始化目标状态函数;随后遍历IR比特码中的每一条指令,根据不同的指令类型对当前的目标状态函数进行更新;本方法反复分析IR比特码中的指令直到目标状态函数不再变化为止;分析完成后,即得到完整的目标状态。

权利要求 :

1.一种C语言的指针类型分析方法,其特征在于,包括:将输入程序的所有C语言源代码转换并整合为LLVM IR比特码;

根据LLVM IR比特码,分析其包含的结构体类型信息,所述结构体类型信息包含结构体指针域的类型信息,根据结构体指针域的类型信息,对结构体指针域集合到类型集合的映射μ(·)进行初始化,得到初始映射μinit(·),其中映射μ(·)以结构体的指针域作为输入,输出该域所有指向的实际类型;

根据μinit(·),对指针变量到类型集合的映射ε(·)进行初始化,得到εinit(·),对目标状态σ=(ε,μ)进行初始化,得到σinit=(εinit,μinit),其中ε为指针变量到类型集合的映射,μ为结构体指针域集合到类型集合的映射;

从初始化的目标状态σinit出发,遍历程序中的所有函数,对每一个函数,遍历函数中的每一条指令,其中每种不同的指令定义了一个不同的状态转移函数TransInst(·),遍历过程中访问一条指令后,目标状态发生相应的状态转移:σ′=TransInst(σ);重复这一步骤直到σ不再变化为止;

输出ε,即程序中所有指针变量可能的实际类型。

2.根据权利要求1所述一种C语言的指针类型分析方法,其特征在于,将输入程序的所有C语言源代码转换并整合为LLVM IR比特码,包括:使用LLVM提供的LTO编译模式对目标程序的C语言源代码进行编译,得到该程序完整的LLVM IR比特码,其中目标程序的C语言源代码包含一个或多个C语言源文件。

3.根据权利要求1所述一种C语言的指针类型分析方法,其特征在于,初始化结构体指针域集合到类型集合的映射μinit(·),包括:对于每个结构体类型,递归地遍历它的所有域;在此过程中,若访问的域是指针域,则初始化该域的实际类型为它的声明类型,即μinit(fd)=typeof(fd),其中结构体的域到类型集合的映射记为μ(·),域记为fd,typeof(·)表示指针域或者指针变量的声明类型。

4.根据权利要求1所述一种C语言的指针类型分析方法,其特征在于,初始化指针变量到类型集合的映射εinit(·),包括:对于程序中的每一个指针变量v,初始化映射ε(·)为εinit(v)=μinit(field(v))∪typeof(v),其中变量到结构体域的映射记为field(·)。

5.根据权利要求1所述一种C语言的指针类型分析方法,其特征在于,每种不同的指令定义了一个不同的状态转移函数TransInst(·),包括:(5‑1)对于类型转换指令

其中RES为类型转换指令的结果,OP为类型转换的输入;

(5‑2)对于取结构体域指针指令(5‑3)对于函数调用指令

其中FARG表示函数的形参,AARG表示函数的实参,n表示参数的个数;

(5‑4)对于比较指令

其中OP1表示第一个比较数,OP2表示第二个比较数;

(5‑5)对于 指令

其中OPi表示第i个操作数,n表示操作数的数量;

(5‑6)对于选择指令

其中OP1和OP2分别表示两个操作数,RES表示指令执行的结果;

其中,ε[x0→a]表示由映射ε所得到的一个新映射ε’, x是函数ε的自变量,x0表示定义域中的任一值,a表示值域中的任一值。

说明书 :

一种C语言的指针类型分析方法

技术领域

[0001] 本发明涉及计算机程序分析领域,尤其涉及一种C语言的指针类型分析方法。

背景技术

[0002] C语言因其较快的运行速度和丰富的程序库而得到广泛的使用。众多高性能的软件均由C语言编写,如Linux/Windows操作系统内核、编译器、数据库以及嵌入式系统应用
等。这些软件为其他应用提供了基础环境以及基础功能,构成了计算机系统的基础设施,因
而具有极广的部署范围和极高的重要性。单以Linux内核的应用之一Android操作系统为
例,截至2019年5月,谷歌发布声明称Android系统的全球用户数量已高达25亿。在如此广泛
的部署数量下,确保C语言程序的正确性和稳定性显得愈发重要。
[0003] 然而越来越大的代码规模对传统软件测试提出了挑战。传统的软件测试一般使用动态测试,即运行程序后输入测试样例观察程序的运行状态。测试样例需要人工编写或是
由程序动态生成。对于小型应用人工编写的测试样例往往足够覆盖程序所有的执行路径,
然而对操作系统级规模的代码进行手工测试则会消耗大量的人力和时间。Linux 5.6版本
的内核已包含了超过3千万行代码,通过手工编写的样例来覆盖所有执行路径不具备可行
性。另一方面,采用模糊测试(fuzzing)技术自动化生成的样例不具备针对性,生成的测试
样例往往无法通过输入合法性判断,或是无法组成有效的语义,使其无法测试到程序内部
大量的条件分支。
[0004] 程序的静态分析技术能够有效的弥补动态测试的不足之处。静态分析技术读取程序代码作为输入并自动化地分析程序代码语义。由于静态分析无需运行程序或是提供合法
输入,因此它的速度更快且能覆盖程序的所有条件分支。不同静态分析方法的结果也不同,
其结果可以是程序的正确性和稳定性,也可以是关于程序的针对性信息,为插桩或是动态
测试提供参考。
[0005] 已有的静态分析技术默认指针声明的类型(简称声明类型)和指针所指向实例的指针类型(简称实际类型)是一致的。然而这一假设在C语言中不完全成立,主要有两点原
因:(1)C语言中存在char*或是void*等类型的通用指针,其声明类型无法反映实际类型。
(2)C语言中存在的强制类型转换可能将指针变量转换为另一指针类型,或是整型,造成声
明类型和实际类型不一致。这种不一致导致声明类型不能完全反映指针的实际类型,使得
静态分析不再具备健全性(soundness),严重影响静态分析的精确性甚至导致错误的结果。

发明内容

[0006] 本发明实施例的目的是提供一种C语言的指针类型分析方法,以解决现有类型分析技术不完整、不准确的问题。
[0007] 为了达到上述目的,本发明实施例所采用的技术方案如下:
[0008] 本发明实施例提供一种C语言的指针类型分析方法,包括:
[0009] 将输入程序的所有C语言源代码转换并整合为LLVM IR比特码;
[0010] 根据LLVM IR比特码,分析其包含的结构体类型信息,所述结构体类型信息包含结构体指针域的类型信息,根据结构体指针域的类型信息,对结构体指针域集合到类型集合
的映射μ(·)进行初始化,得到初始映射μinit(·),其中映射μ(·)以结构体的指针域作为
输入,输出该域所有指向的实际类型;
[0011] 根据μinit(·),对指针变量到类型集合的映射ε(·)进行初始化,得到εinit(·),对目标状态σ=(ε,μ)进行初始化,得到σinit=(εinit,μinit),其中ε为指针变量到类型集合的映
射,μ为结构体指针域集合到类型集合的映射;
[0012] 从初始化的目标状态σinit出发,遍历程序中的所有函数,对每一个函数,遍历函数中的每一条指令,其中每种不同的指令定义了一个不同的状态转移函数TransInst(·),遍
历过程中访问一条指令后,目标状态发生相应的状态转移:σ′=TransInst(σ);重复这一步
骤直到σ不再变化为止;
[0013] 输出ε,即程序中所有指针变量可能的实际类型。
[0014] 进一步地,将输入程序的所有C语言源代码转换并整合为LLVM IR比特码,包括:
[0015] 使用LLVM提供的LTO编译模式对目标程序的C语言源代码进行编译,得到该程序完整的LLVM IR比特码,其中目标程序的C语言源代码包含一个或多个C语言源文件。
[0016] 进一步地,初始化结构体指针域集合到类型集合的映射μinit(·),包括:
[0017] 对于每个结构体类型,递归地遍历它的所有域;在此过程中,若访问的域是指针域,则初始化该域的实际类型为它的声明类型,即μinit(fd)=typeof(fd),其中结构体的域
到类型集合的映射记为μ(·),域记为fd,typeof(·)表示指针域或者指针变量的声明类
型。
[0018] 进一步地,初始化指针变量到类型集合的映射εinit(·),包括:
[0019] 对于程序中的每一个指针变量v,初始化映射ε(·)为εinit(v)=μinit(field(v))∪typeof(v),其中变量到结构体域的映射记为field(·)。
[0020] 进一步地,每种不同的指令定义了一个不同的状态转移函数TransInst(·),包括:
[0021] (5‑1)对于类型转换指令{typeof
(RES)}]),其中RES为类型转换指令的结果,OP为类型转换的输入;
[0022] (5‑2)对于取结构体域指针指令
[0023] (5‑3)对于函数调用指令其中FARG表示函数的形参,AARG表示函数的实参,n表示参数的
个数;
[0024] (5‑4)对于比较指令其中OP1表示第一个比较数,OP2表示第二个比较数;
[0025] (5‑5)对于 指令其中OPi表示第i个操作数,n表示操作数的数量;
[0026] (5‑6)对于选择指令其中OP1和OP2分别表示两个操作数,RES表示指令执行的结果;
[0027] 其中,ε[x0→a]表示由映射ε所得到的一个新映射ε’, x是函数ε的自变量,x0表示定义域中的任一值,a表示值域中的任一值。
[0028] 根据以上技术方案,本发明的有益效果是,本发明能根据程序语义识别通用指针的实际类型,也能正确地处理强制转换语义,弥补了现有类型分析技术的不足;本发明对函
数的形参也进行了分析,实现了跨过程的静态分析,确保了分析结果的健全性。

附图说明

[0029] 此处所说明的附图用来提供对本发明的进一步理解,构成本发明的一部分,本发明的示意性实施例及其说明用于解释本发明,并不构成对本发明的不当限定。在附图中:
[0030] 图1为本发明实施例提供的一种C语言的指针类型分析方法的流程图。

具体实施方式

[0031] 为使本申请的目的、技术方案和优点更加清楚,下面将结合本申请具体实施例及相应的附图对本申请技术方案进行清楚、完整地描述。显然,所描述的实施例仅是本申请一
部分实施例,而不是全部的实施例。基于本申请中的实施例,本领域普通技术人员在没有做
出创造性劳动前提下所获得的所有其他实施例,都属于本申请保护的范围。
[0032] 图1为本发明实施例提供的一种C语言的指针类型分析方法的流程图;本实施例提供一种C语言的指针类型分析方法,本实施例以Android Linux操作系统内核中的指针类型
分析为例来进行说明,该方法包括以下步骤:
[0033] 步骤S101,将输入程序的所有C语言源代码转换并整合为LLVM IR比特码;
[0034] 具体地,开启Android Linux操作系统内核编译的LTO选项,使用LLVM提供的LTO模式编译内核,得到Android Linux操作系统完整的LLVM IR比特码;IR比特码包含了整个程
序完整的类型信息和语义信息,且提供了完整简洁的分析接口,便于后续的跨过程静态分
析。
[0035] 步骤S102,根据LLVM IR比特码,分析其包含的结构体类型信息,所述结构体类型信息包含结构体指针域的类型信息,根据结构体指针域的类型信息,对结构体指针域集合
到类型集合的映射μ(·)进行初始化,得到初始映射μinit(·),其中映射μ(·)以结构体的
指针域作为输入,输出该域所有指向的实际类型;
[0036] 具体地,对于Android Linux操作系统内核IR比特码中包含的每个结构体类型,遍历它的所有域,对于嵌套的结构体则采用深度优先搜索策略(Depth‑first search,DFS);
在此过程中,若访问的域是指针域,则初始化该域的实际类型为它的声明类型,即μinit(fd)
=typeof(fd),其中结构体的域到类型集合的映射记为μ(·),域记为fd,typeof(·)表示
指针域或者指针变量的声明类型。
[0037] 步骤S103,对指针变量到类型集合的映射ε(·)进行初始化,得到εinit(·),对目标状态σ=(ε,μ)进行初始化,得到σinit=(εinit,μinit),其中ε为指针变量到类型集合的映
射,μ为结构体指针域集合到类型集合的映射;
[0038] 具体地,对于Android Linux操作系统内核IR比特码中的每一个指针类型的变量v,初始化映射ε(·)为εinit(v)=μinit(field(v))∪typeof(v),其中变量到结构体域的映射
记为field(·)。目标状态σ包括映射ε和映射μ,是本发明对程序进行分析的目标。
[0039] 步骤S104,从初始化的目标状态σinit出发,遍历程序中的所有函数;对每一个函数,遍历函数中的每一条指令;每种不同的指令定义了一个不同的状态转移函数TransInst
(·),遍历过程中访问一条指令后,目标状态发生相应的状态转移:σ′=TransInst(σ);重复
这一步骤直到σ不再变化为止;具体地,其中状态转移函数TransInst(·),包含如下子步骤:
[0040] (5‑1)对于类型转换指令其中RES为类型转换指令的结果,OP为类型转换的输入;
[0041] (5‑2)对于取结构体域指针指令
[0042] (5‑3)对于函数调用指令其中FARG表示函数的形参,AARG表示函数的实参,n表示参数的
个数;
[0043] (5‑4)对于比较指令其中OP1表示第一个比较数,OP2表示第二个比较数;
[0044] (5‑5)对于 指令其中OPi表示第i个操作数,n表示操作数的数量;
[0045] (5‑6)对于选择指令其中OP1和OP2分别表示两个操作数,RES表示指令执行的结果。
[0046] 其中,ε[x0→a]表示由映射ε所得到的一个新映射ε’, x是函数ε的自变量,x0表示定义域中的任一值,a表示值域中的任一值。
[0047] 每种状态转移函数为每种不同的指令进行了精确的建模,在保留精确性的同时确保了静态分析的健全性,也即覆盖了所有的可能出现的情况。以Android Linux内核中的一
段代码为例:
[0048]
[0049] 其中第516行中的container_of其实是一个强制类型转换指令,即timer指针同时指向了struct timerqueue_node类型和struct hrtimer类型,仅仅根据timer指针的声明
类型只能得到该指针指向struct hrtimer类型;本方法则通过对强制类型转换指令的语义
进行建模,能成功分析得到该指针同时指向两种类型。
[0050] 步骤S105,输出ε,即程序中所有指针变量可能的实际类型。
[0051] 以上所述仅为本发明的较佳实施例而已,并不用以限制本发明,凡在本发明的精神和原则之内,所作的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。