一种利用数据流分析算法分析c代码中的内存安全的方法
技术领域
1.本发明涉及数据流分析算法、静态分析工具开发领域,特别涉及一种利用数据流分析算法分析c代码中的内存安全的方法。
背景技术:
2.现代程序语言对于堆上内存空间的回收,无外乎两种方式:一种是使用者在代码中显式地调用内存回收函数,手动释放内存;另一种是引入自动的垃圾回收机制。rust内存管理的核心是通过所有权,规定堆上的每块内存在同一时刻只具有一个所有权拥有者,rust 通过静态分析的方法,精确分析出每个变量的作用域,当所有权拥有者的作用域结束后,堆上的这块内存空间也会被自动释放掉;而c 则需要手动地解决堆上内存空间的申请和释放,容易造成很多内存安全问题。
3.rust在内存安全方面比c做得相对更好,但大部分linux内核代码都用c写成,短时间内不会改为rust。现存分析技术包括plural,但它主要针对的是java的引用。另一个针对c的内存分析工具是微软的checked-c,但它针对的是数组或缓冲区越界问题,而非变量所有权。
技术实现要素:
4.为了解决上述技术问题,本发明中披露了一种利用数据流分析算法分析c代码中的内存安全的方法,本发明的技术方案是这样实施的:
5.一种利用数据流分析算法分析c代码中的内存安全的方法,将c 语言内存指令定义成形式化后的指令集,然后进行如下操作,
6.静态分析出代码需要并给对应指针添加标记的位置,并为代码自动添加标记;
7.将上述代码转化成抽象语法树,并对其每一个指令进行类型检查,同时对涉及到的指针权限转移或借用语句进行修改,使之在静态单赋值中有所区分;
8.对抽象语法树进行线性化,得到静态单赋值形式的控制流图,进行数据流分析,得到收敛的权限映射表的结果;
9.利用数据流分析算法迭代稳定后的结果,利用错误检查函数检查是否存在内存安全问题。
10.优选地,所述指针包括拥有所有权和不拥有所有权两种类型。
11.优选地,所述指令集包括内存分配、内存释放、内存所有权转移、内存所有权借用、强制类型转化、指针离开作用域、取指令、存指令、合并指令和函数调用指令。
12.优选地,错误检测方法包括内存泄漏检测、多次释放检查、在被借走时转移或释放检查、释放后使用。
13.优选地,所述抽象语法树包括函数参数和返回值的信息,并基于此建立了函数对应的指针权限映射表,指针权限映射表包含了所有从变量到它所具有的指针权限的映射。
14.优选地,分析前,对传入的文件进行预处理,遍历整个文件的代码,查找其中全部
的指针并观测指针的行为,对指针是否有内存分配或释放的行为进行分析,添加不同的指针标记;如果有内存释放或分配、或对具有所有权的指针进行转移的行为,代表它对一块内存具有所有权,应为这个指针添加具有所有权的标记;反之,认为这个指针仅借走了所有权,添加不具有所有权的标记。
15.优选地,对于抽象语法树中的每一个函数,便利其中的每一条指令,如果涉及到所有权转移,如将拥有一块空间的指针转移给另一个拥有所有权的指针,添加指针所有权需要转移的注释;如果涉及到所有权借出,如一个没有所有权的指针借走了另一个指针的权限,添加指针所有权被借出的注释。
16.优选地,数据分析的具体步骤如下,
17.对每个函数逐一进行分析,分别记录它们参数和返回值的权限种类,即拥有所有权还是不拥有所有权;
18.如果是拥有所有权的参数和返回值,在函数调用时转移所有权;
19.如果是不拥有所有权的参数和返回值,由于不知道函数内部的情况,在函数调用时将权限记为“*”;
20.如果不是指针,不涉及到所有权的变化,记为“非指针”;
21.然后为每条涉及内存的指令定义权限映射表的转移方程,即由一个指针权限经过一条指令后可能转变为的指针权限,以及不同权限映射表的合并操作;
22.将抽象语法树转化为静态单赋值,对于每个函数分别进行分析。
23.优选地,内存错误检查具体算法如下:
24.(a)将函数入口点的指针权限映射表初始化为函数参数权限,其余每个基本块的入口点的指针权限映射表初始化为空;
25.(b)对于每个基本块的每条指令进行顺序分析,得到一条指令结束后的指针权限映射表并传递给下一条指令,直至基本块出口处,同时,记录是否有基本块的指针权限映射表发生了变化;
26.(c)如果指针权限映射表发生变化,将位于每个基本块父节点处的基本块的出口处指针权限映射表合并,并且传递给这个块,作为该基本块的入口处权限映射表。重复(b)和(c)操作;
27.(d)如果指针权限映射表没有发生变化,结束迭代,此时得到的结果是收敛的指针权限映射表;
28.(e)重新遍历每条指令和执行这条指令之前的指针权限映射表,利用内存错误检测机制判断是否出现不安全的行为。
29.实施本发明的技术方案可解决现有技术中内存检测技术还存在弊端的技术问题;实施本发明的技术方案,通过基于c语言中一系列常见的涉及内存的指令,定义了形式化后的指令集,定义了一系列内存错误检测方法,便于检测内存安全。
附图说明具体实施方式
30.下面对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例
仅仅是本发明一部分实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有作出创造性劳动前提下所获得的所有其他实施例,都属于本发明保护的范围。
31.实施例
32.一种利用数据流分析算法分析c代码中的内存安全的方法,将c 语言内存指令定义成形式化后的指令集,然后进行如下操作,
33.静态分析出代码需要并给对应指针添加标记的位置,并为代码自动添加标记;所述指针包括拥有所有权和不拥有所有权两种类型。
34.将c代码转化成抽象语法树(ast),对抽象语法树中每条指令进行类型检查,同时对抽象语法树里涉及到的指针权限转移/借用语句进行不同的修改,使之在静态单赋值(ssa)中有所区分。这一步称为注释。
35.对抽象语法树进行线性化,得到静态单赋值形式的控制流图,进行数据流分析,得到收敛的权限映射表的结果;
36.利用数据流分析算法迭代稳定后的结果,利用错误检查函数检查是否存在内存安全问题。
37.本实施例基于c语言中一系列常见的涉及内存的指令,定义了形式化后的指令集。其中包括:内存分配malloc,在堆上为具有所有权的指针分配一块空间;内存释放free,将指针所指向堆上的空间释放;内存所有权转移move,将一个具有所有权的指针的权限转移给另一个具有所有权的指针;内存所有权借用borrow,将一个具有所有权的指针的权限临时借给另一个不具有所有权的指针;强制类型转化ptrcast,将一个指针强制转化成另一个不同类型的指针;指针离开作用域dead,一个指针的作用域结束,后续不再使用;取指令 load,将一个指针的某个域取出并存入另一个相同类型的指针,此时需要对指针别名进行分析;存指令store,将某个指针的空间存入另一个指针的相同类型的域,此时需要对指针别名进行分析;合并指令 phi,某个指针的内存空间有多个来源,分别为(phi,1),(phi,2)...;函数调用指令call f,分别传递参数和返回值的内存空间权限。
38.这个指令集包含了可能对指针的权限发生影响的指令类型。在数据流分析的过程中,对这个指令集内的每一条指令进行分析。
39.优选地,错误检测方法包括内存泄漏检测、多次释放检查、在被借走时转移或释放检查、释放后使用。
40.所述抽象语法树包括函数参数和返回值的信息,并基于此建立了函数对应的指针权限映射表。
41.指针权限映射表包含了所有从变量到它所具有的指针权限的映射。
42.使用者将待分析的c语言代码作为输入,传入检测系统。
43.分析前,对传入的文件进行预处理,遍历整个文件的代码,查找其中全部的指针并观测指针的行为,对指针是否有内存分配或释放的行为进行分析,添加不同的指针标记;如果有内存释放或分配、或对具有所有权的指针进行转移的行为,代表它对一块内存具有所有权,应为这个指针添加具有所有权的标记;反之,认为这个指针仅借走了所有权,添加不具有所有权的标记。
44.对代码进行词法和文法解析,生成抽象语法树。对于抽象语法树中的每一个函数,
便利其中的每一条指令,如果涉及到所有权转移,如将拥有一块空间的指针转移给另一个拥有所有权的指针,添加指针所有权需要转移的注释;如果涉及到所有权借出,如一个没有所有权的指针借走了另一个指针的权限,添加指针所有权被借出的注释。这一步的目的是在静态单赋值中显示出两者的区别。同时,这一步还进行了类型检查,分析有没有错误的权限转化,比如将不具有所有权的指针的指针转移给拥有所有权的指针的指针。
45.对代码进行数据流分析。这一步是关键步骤。
46.首先,遍历抽象语法树,其中每一个函数是一个节点。抽象语法树包含了函数参数和返回值的信息,因此建立了函数的权限映射表,对每个函数逐一进行分析,分别记录它们参数和返回值的权限种类,即拥有所有权还是不拥有所有权;如果是拥有所有权的参数和返回值,在函数调用时转移所有权;如果是不拥有所有权的参数和返回值,由于不知道函数内部的情况,在函数调用时将权限记为“*”;如果不是指针,不涉及到所有权的变化,记为“非指针”。
47.其次,为每条涉及内存的指令定义权限映射表的转移方程,即由一个指针权限经过一条指令后可能转变为的指针权限,以及不同权限映射表的合并操作。将抽象语法树转化为静态单赋值,对于每个函数分别进行分析。静态单赋值表现为控制流图,由多个基本块基本块之间的跳转连接构成。将函数入口点的初始权限映射表定义为该函数参数与其指针权限的映射集合,其余基本块的初始权限映射表定义为空。在每个基本块内部,顺序遍历每条指令,不断传递并更新指针权限映射表。在基本块内部的第一次迭代完成后,对于拥有父节点的基本块,遍历父节点并将它们出口处的权限映射表合并,传递给该基本块。重复块内的迭代和块外的合并操作,直至收敛,得到最终稳定的权限映射表的结果。
48.内存错误检查具体算法如下:
49.(a)将函数入口点的指针权限映射表初始化为函数参数权限,其余每个基本块的入口点的指针权限映射表初始化为空;
50.(b)对于每个基本块的每条指令进行顺序分析,得到一条指令结束后的指针权限映射表并传递给下一条指令,直至基本块出口处,同时,记录是否有基本块的指针权限映射表发生了变化;
51.(c)如果指针权限映射表发生变化,将位于每个基本块父节点处的基本块的出口处指针权限映射表合并,并且传递给这个块,作为该基本块的入口处权限映射表。重复(b)和(c)操作;
52.(d)如果指针权限映射表没有发生变化,结束迭代,此时得到的结果是收敛的指针权限映射表;
53.(e)重新遍历每条指令和执行这条指令之前的指针权限映射表,利用内存错误检测机制判断是否出现不安全的行为。
54.本实施例的错误检测中定义了指令和指针权限表所需要满足的规则,若违背这些规则,则判断程序出现错误。例如,对于内存泄漏检查,定义程序出口处的指针权限表应该为空(即程序内分配的所有内存在程序结束后都已经被释放),如果不为空,则产生了内存泄漏问题;对于多次释放检查,如果指针权限表中一个指针记录为不拥有所有权(即已经被释放),下一条指令中又对这个指针进行释放操作,则判断为多次释放。对于被借时转移或释放检查,当指针权限映射表中一个指针记录为被借走,而下一条指令中将这个指针的所
有权转移给另外的指针或将这个指针的内存释放(包括其他要求指针所有权的指令),会造成悬空指针,判断产生了此类错误;对于释放后使用检查,如果指令中使用一个指针权限表显示为不拥有所有权(即已被释放)的指针,例如解引用,判断产生了释放后使用的错误。
55.需要指出的是,以上所述仅为本发明的较佳实施例而已,并不用以限制本发明,凡在本发明的精神和原则之内,所作的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。
技术特征:
1.一种利用数据流分析算法分析c代码中的内存安全的方法,其特征在于:将c语言内存指令定义成形式化后的指令集,然后进行如下操作,静态分析出代码需要并给对应指针添加标记的位置,并为代码自动添加标记;将上述代码转化成抽象语法树,并对其每一个指令进行类型检查,同时对涉及到的指针权限转移或借用语句进行修改,使之在静态单赋值中有所区分;对抽象语法树进行线性化,得到静态单赋值形式的控制流图,进行数据流分析,得到收敛的权限映射表的结果;利用数据流分析算法迭代稳定后的结果,利用错误检查函数检查是否存在内存安全问题。2.根据权利要求1所述的一种利用数据流分析算法分析c代码中的内存安全的方法,其特征在于:所述指针包括拥有所有权和不拥有所有权两种类型。3.根据权利要求2所述的一种利用数据流分析算法分析c代码中的内存安全的方法,其特征在于:所述指令集包括内存分配、内存释放、内存所有权转移、内存所有权借用、强制类型转化、指针离开作用域、取指令、存指令、合并指令和函数调用指令。4.根据权利要求3所述的一种利用数据流分析算法分析c代码中的内存安全的方法,其特征在于:错误检测方法包括内存泄漏检测、多次释放检查、在被借走时转移或释放检查、释放后使用检查。5.根据权利要求4所述的一种利用数据流分析算法分析c代码中的内存安全的方法,其特征在于:所述抽象语法树包括函数参数和返回值的信息,数据流分析算法根据抽象语法树计算函数对应的指针权限映射表,指针权限映射表包含了所有从变量到它所具有的指针权限的映射。6.根据权利要求5所述的一种利用数据流分析算法分析c代码中的内存安全的方法,其特征在于:分析前,对传入的文件进行预处理,遍历整个文件的代码,查找其中全部的指针并观测指针的行为,对指针是否有内存分配或释放的行为进行分析,添加不同的指针标记;如果有内存释放或分配、或对具有所有权的指针进行转移的行为,代表它对一块内存具有所有权,应为这个指针添加具有所有权的标记;反之,认为这个指针仅借走了所有权,添加不具有所有权的标记。7.根据权利要求6所述的一种利用数据流分析算法分析c代码中的内存安全的方法,其特征在于:对于抽象语法树中的每一个函数,遍历其中的每一条指令,如果涉及到所有权转移,如将拥有一块空间的指针转移给另一个拥有所有权的指针,添加指针所有权需要转移的注释;如果涉及到所有权借出,如一个没有所有权的指针借走了另一个指针的权限,添加指针所有权被借出的注释。8.根据权利要求7所述的一种利用数据流分析算法分析c代码中的内存安全的方法,其特征在于:数据分析的具体步骤如下,对每个函数逐一进行分析,分别记录它们参数和返回值的权限种类,即拥有所有权还是不拥有所有权;如果是拥有所有权的参数和返回值,在函数调用时转移所有权;如果是不拥有所有权的参数和返回值,由于不知道函数内部的情况,在函数调用时将权限记为“*”;
如果不是指针,不涉及到所有权的变化,记为“非指针”;然后为每条涉及内存的指令定义权限映射表的转移方程,即由一个指针权限经过一条指令后可能转变为的指针权限,以及不同权限映射表的合并操作;将抽象语法树转化为静态单赋值,对于每个函数分别进行分析。9.根据权利要求8所述的一种利用数据流分析算法分析c代码中的内存安全的方法,其特征在于:内存错误检查具体算法如下:(a)将函数入口点的指针权限映射表初始化为函数参数权限,其余每个基本块的入口点的指针权限映射表初始化为空;(b)对于每个基本块的每条指令进行顺序分析,得到一条指令结束后的指针权限映射表并传递给下一条指令,直至基本块出口处,同时,记录是否有基本块的指针权限映射表发生了变化;(c)如果指针权限映射表发生变化,将位于每个基本块父节点处的基本块的出口处指针权限映射表合并,并且传递给这个块,作为该基本块的入口处权限映射表。重复(b)和(c)操作;(d)如果指针权限映射表没有发生变化,结束迭代,此时得到的结果是收敛的指针权限映射表;(e)重新遍历每条指令和执行这条指令之前的指针权限映射表,利用内存错误检测机制判断是否出现不安全的行为。
技术总结
本发明提供了一种利用数据流分析算法分析C代码中的内存安全的方法。将指令定义成形式化后的指令集,进行如下操作,静态分析出代码需要并给指针添加标记;将代码转化成抽象语法树,并对其每一个指令进行类型检查,同时对涉及到的指针权限转移或借用语句进行修改,使之在静态单赋值中有所区分;对抽象语法树进行线性化,得到静态单赋值形式的控制流图,进行数据流分析,得到收敛的权限映射表的结果;利用数据流分析算法迭代稳定后的结果,利用错误检查函数检查是否存在内存安全问题。其中本发明的有益效果是:基于C语言中一系列常见的涉及内存的指令,定义了形式化后的指令集,定义了一系列内存错误检测方法,便于检测内存安全。全。
技术研发人员:贾枭 孙振东
受保护的技术使用者:上海那一科技有限公司
技术研发日:2021.10.15
技术公布日:2022/3/8