法律状态公告日
法律状态信息
法律状态
2023-05-26
实质审查的生效 IPC(主分类):G06F11/36 专利申请号:2023101429831 申请日:20230221
实质审查的生效
2023-05-09
公开
发明专利申请公布
技术领域
本发明属于程序语言领域,具体涉及一种针对Rust编程语言中UNSAFE代码片段缺陷的检测方法。
背景技术
软件工程师在不到30%的Rust库中使用关键字unsafe,但由于Unsafe Rust隐藏在库调用链的某处,因此超过一半的Rust编译器无法完全静态检查。因此为了更好更安全的使用Rust,应该谨慎使用unsafe rust,并且unsafe block范围尽量是少的、小的并且是自包含的(封装良好的,只在包的内部使用)。
目前编译器主要对确定的五种操作进行识别(解引用原始指针、调用不安全的函数或方法、访问或修改可变静态变量、实现一个unsafe trait、访问unions字段),如果开发者在代码中使用这五种操作,则必须使用unsafe修饰,否则会报告错误。此外Rust编程语言并没有对函数或方法是否标记unsafe有强制性约束。
编译器只提醒必须使用unsafe标记的五种操作,因此对于unsafe范围开发者有时修饰的范围不够精确。并且对于函数或方法是否标记unsafe函数全由开发者自己决定,并没有强制性的要求。并且通过对Github相关的调查,对于unsafe rust主要发现了两个关键问题:
一是unsafe的范围不够精确,也就是unsafe block在开发者标记的时候很有可能将unsafe的范围标记得很大,或者为了方便将safe rust代码标记进去,开发者在编写代码的过程中很容易将安全的代码包含进来,使unsafe的范围不够精确,增加后期代码审查的难度,使用图1作为概念验证(PoC)示例来演示此类案例。该代码片段是第一种问题众多实例其中的一个,开发者将前四行更改为后两行语句,其中load()是开发者项目中的安全函数,stopBaker()是第三方库中的unsafe函数,可以看出来,开发者的unsafe block的范围不精确。开发者在编写代码的过程中很容易将安全的代码包含进来,使unsafe的范围不够精确,增加后期代码审查的难度,明确的unsafe block可以更容易地在问题发生时追踪问题的根源。
二是对于函数或方法是否应标记为unsafe并没有硬性的约束,从而导致了有一部分开发者将应该标记为unsafe的函数或方法未进行标记,无需标记unsafe的函数或方法而对其进行标记,给Rust社区造成安全隐患。因此开发相应的算法解决这两个关于unsafe代码片段缺陷很有必要,为Rust编程语言社区减少安全隐患,并且能够使使用Rust开发的软件项目更加安全。
发明内容
针对现有技术的不足,本发明设计一种针对Rust编程语言中UNSAFE代码片段缺陷的检测方法;使用HIR来快速收集关注的代码区域(开发者编写的unsafe代码片段),利用HIR中的结构信息识别语句结构;然后使用MIR来推理代码语义识别真正的不安全操作。
一种针对Rust编程语言中UNSAFE代码片段缺陷的检测方法,具体包括以下内容:
步骤1:基于rustc_lint模块,利用HIR判断程序语言中表达式是否包含在开发者编写的unsafeblock中;所述HIR为高级中间表示;
Rust的源代码首先经由词法分析生成抽象语法树AST,对开发者编写的源代码进行脱糖;经过查询系统生成HIR,然后对其进行类型检查以及剥离unsafe关键字,再次经过查询系统生成中级中间表示MIR,然后进行借用检查、代码优化,最后转化为LLVM IR;
HIR包含代码的结构信息;通过HIR依次找到包含当前表达式的节点,如果该节点的类型为表达式,并且表达式的类型为block,则判断该block是否为开发者编写的unsafeblock,如果是说明当前表达式包含于开发者编写的unsafe block中,继续进行下一步处理,否则就继续对下一个表达式进行判断;
步骤2:利用HIR对表达式的结构进行解析;
Rust中表达式共计32种,表达式类型共分为两大类,一类是没有包含block的,一类是包含block的,并且block、语句、表达式三者递归地相互嵌套到任意深度;
类型为block的表达式,结构为一个语句数组和一个作为该block返回值的表达式,因此对于类型为block的表达式,分为两种情况,block中只包含expr,直接对其进行分析,如果包含stmt,对每个stmt继续解析其结构对包含其中的表达式继续进行上述相同处理方法进行分析;
步骤3:利用MIR分析识别不安全的操作;
步骤3.1:识别解引用原始指针的操作;
首先检查表达式是否是一元操作(!x、*x、-x)并且判断是否为解引用(*x),通过rustc_mir_build得到表达式的类型检查信息,判断其是否为unsafe指针;如果是,略过包含该表达式的语句,继续对其他表达式进行相同处理;
步骤3.2:识别是否调用不安全的函数或方法;
检查表达式是否为函数调用或方法调用,通过rustc_mir_build得到表达式的类型检查信息,得到函数或方法def_id,再从TyCtxt中查询到该函数或方法的函数签名,判断其调用的是否为unsafe函数或方法;如果是,略过包含该表达式的语句,继续对其他表达式进行相同处理;
步骤3.3:识别访问可变的静态变量的操作;
对于自定义类型的变量,通过rustc_mir_build得到该变量的类型,并且得到该类型的def_id,判断其是否为可变静态变量;如果是,略过包含该表达式的语句,继续对其他表达式进行相同处理;
步骤4:对在开发者编写的unsafeblock中的安全表达式或语句进行报告;
在经过步骤1-3的分析之后,将安全的表达式以语句为单位进行报告,当语句的右侧是不安全的则将语句的左侧进行报告;
整个block是安全的,就对整个块进行报告;
对于if/match/while等判断条件即不会出现复杂的嵌套表达式,也直接进行报告。
本发明有益技术效果:
与现有技术相比,本发明可以打印警告以供开发者尽可能多地发现自己编写的unsafe block中安全的表达式或语句(无需使用unsafe修饰)。因此,开发者可以手动检查有缺陷的代码片段,然后进行一些修正,最后通过该工具重新编译整个项目以验证警告是否消除。执行本发明来检测一些真实世界(GitHub)的rust crates中的unsafe block范围精确的问题,对存在unsafe block范围不精确问题的存储库进行报告。
附图说明
图1本发明实施例UNSAFE RUST范围不精确的代码片段;
图2本发明一种针对Rust编程语言中UNSAFE代码片段缺陷的检测方法整体架构图;
图3本发明实施例检测报告和开发者更正代码的效果对比图。
具体实施方式
下面结合附图和实施例对本发明做进一步说明;
本发明的实现方式依托rustc_lint模块,所述rustc_lint模块是一个专门用来实现各种代码质量检测分析过程(Lint pass)的模块;Lint是代码静态分析工具的一种,最早是来源于C语言;Lint工具通常会检查代码中潜在的问题和错误,Lint工具除了标识错误外,还会带有一定的fix/refactor suggest和auto-fix的能力;在工程中引入Lint工具可以有效的减少错误,提高整体的工程质量;此外,对一种编程语言来说,Lint工具通常也是其他工具研发的前置条件,例如IDE插件的错误提示,CI的Pipeline检测等;并且依托rustc_lint模块在编译的中后阶段实现,因为涉及到各种类型信息相关的分析,需要编译器生成的各种类型检查信息,因此选择了一个比较靠后的执行时机。其中LateLintPasstrait提供了一系列方法,使用的是check_expr(_,LateContext,_),它能够对源代码文件中的每个表达式进行调用。LateContext结构包含了本发明所需要的类型检查信息。
一种针对Rust编程语言中UNSAFE代码片段缺陷的检测方法,图2概述了方法的整体框架它输入每个表达式的HIR,并输出安全的表达式或语句的警告(需要移出unsafeblock),使unsafe块的范围尽量足够精确。具体包括以下内容:
步骤1:基于rustc_lint模块,利用HIR判断程序语言中表达式是否包含在开发者编写的unsafeblock中;所述HIR(High-Level Intermediate Representation)为高级中间表示;UNSAFE RUST范围不精确的代码片段如附图1所示;
Rust的源代码首先经由词法分析生成抽象语法树AST,对开发者编写的源代码进行脱糖;经过查询系统生成HIR,然后对其进行类型检查以及剥离unsafe关键字,再次经过查询系统生成中级中间表示MIR,然后进行借用检查、代码优化,最后转化为LLVM IR;
HIR包含代码的结构信息;通过HIR依次找到包含当前表达式的节点,如果该节点的类型为表达式,并且表达式的类型为block,则判断该block是否为开发者编写的unsafeblock,如果是说明当前表达式包含于开发者编写的unsafe block中,继续进行下一步处理,否则就继续对下一个表达式进行判断;
步骤2:利用HIR对表达式的结构进行解析;
Rust中表达式共计32种,表达式类型共分为两大类,一类是没有包含block的(如结构体表达式、break表达式、continue表达式等),一类是包含block的(如block表达式、if表达式、match表达式等),并且block、语句、表达式三者递归地相互嵌套到任意深度;
因此如果直接对表达式进行分析,如果是不需要使用unsafe关键字标记的表达式就要进行报告,否则会造成“冗余”报告的问题,因为同一个表达式可能包含很多个表达式;此外一些非常规的代码结构在HIR中也会被解析成其它结构(由源代码脱糖而来),需要进行进一步的解析代码结构进行识别。例如:while表达式在HIR中会被转化为loop和if表达式,for表达式在HIR中会被转化为loop和match表达式。对于if\match\while等结构中的部分表达式(编写判断条件的地方)直接进行分析,因为基本没有在写判断条件的这些地方写复杂包含嵌套的表达式,如果是安全的直接进行报告。
类型为block的表达式,结构为一个语句数组和一个作为该block返回值的表达式,因此对于类型为block的表达式,分为两种情况,block中只包含expr,直接对其进行分析,如果包含stmt,对每个stmt继续解析其结构对包含其中的表达式继续进行上述相同处理方法进行分析;
步骤3:利用MIR分析识别不安全的操作;
步骤3.1:识别解引用原始指针的操作;
首先检查表达式是否是一元操作(!x、*x、-x)并且判断是否为解引用(*x),通过rustc_mir_build得到表达式的类型检查信息,判断其是否为unsafe指针;如果是,略过包含该表达式的语句,继续对其他表达式进行相同处理;
步骤3.2:识别是否调用不安全的函数或方法;
检查表达式是否为函数调用或方法调用,通过rustc_mir_build得到表达式的类型检查信息,得到函数或方法def_id,再从TyCtxt中查询到该函数或方法的函数签名,判断其调用的是否为unsafe函数或方法;如果是,略过包含该表达式的语句,继续对其他表达式进行相同处理;
步骤3.3:识别访问可变的静态变量的操作;
对于自定义类型的变量,通过rustc_mir_build得到该变量的类型,并且得到该类型的def_id,判断其是否为可变静态变量;如果是,略过包含该表达式的语句,继续对其他表达式进行相同处理;
步骤4:对在开发者编写的unsafeblock中的安全表达式或语句进行报告;
在经过步骤1-3的分析之后,将安全的表达式以语句为单位进行报告,当语句的右侧是不安全的则将语句的左侧进行报告;
整个block是安全的,就对整个块进行报告;
对于if/match/while等判断条件即不会出现复杂的嵌套表达式,也直接进行报告。检测报告和开发者更正代码的效果对比图如附图3所示。
本发明使用HIR和MIR的混合分析技术。值得强调的是多个IR级别的混合使用是非常规的,但是对于本发明所要解决问题却是必要的,该技术主要是为了对unsafe代码片段的范围进行精确化,首先需要定位到unsafe block(利用HIR),然后识别unsafe操作(利用MIR)和调用到的unsafe函数或方法,对必须使用unsafe关键字的语句进行标记,与最初的unsafe block的范围进行比较,做出相应更改;本发明提出了针对函数参数的数据流分析技术,找出函数参数的别名传播链。这是对函数或方法进行判断是否标记unsafe关键字所需要的关键技术,并结合fuzz测试技术对目标函数进行测试以判断函数是否必须标记unsafe关键字。
机译: 青霉素结合蛋白,核酸,抗体或抗体片段,药物,药物组合物,至少一种青霉素结合蛋白或其片段或变异体或片段,至少一种核酸和至少一种抗体或抗体片段的用途,针对脑膜炎奈瑟菌的青霉素结合蛋白,核酸,抗体或抗体片段感染的体外抗体检测方法,至少一种青霉素结合蛋白或其片段或变异体或变异体,至少一种核酸的药物组合物酸和至少一种针对哺乳动物生物样品中脑膜炎奈瑟氏菌感染的抗体以及来自哺乳动物生物样品中的矿业性奈瑟氏球菌感染的体外诊断和单克隆抗体
机译: 用于检测流体中至少一种物质的装置,用于生产该装置的方法以及用于检测至少一种针对另一种流体的物质的方法
机译: 分析方法例如用于检测和定位系统封装中缺陷的系统封装,包括在检测到点的到达时刻之后启动针对点的测试序列的应用