Rust语言在核电安全级仪控研发应用探讨

2023-05-17 07:43常泽海
仪器仪表用户 2023年6期
关键词:开发人员指针C语言

杨 斌,蒋 维,常泽海

(1.西安交通大学核科学与技术学院,西安 710049;2.中国核动力研究设计院核反应堆系统设计技术重点实验室,成都 610213)

0 引言

随着核电领域的自动化和数字化发展,核电仪控软件在整个核电系统中扮演的角色越来越重要,这对核电仪控软件提出了更高的安全性和可靠性要求。由于C语言的高性能且能够直接操作硬件的特性,目前大部分核电仪控软件采用C语言进行开发。然而,C语言的不安全特性使得开发的软件系统易出现安全性问题,核电安全级仪控软件开发过程中必须通过遵循严格的安全标准规范以及引入一系列软件开发活动以规避C语言的安全风险。目前常用的标准有:MSRA-2004、GJB-5369-2005《航天型号软件C语言安全子集》、GB/T28169-2011《嵌入式软件C语言编码规范》[1]等,软件开发活动包括软件代码静态分析、软件测试和软件V&V活动[2]。一方面,检测工具的检测能力和准确性直接影响检测结果,代码检测工具存在误报或漏检的可能;另一方面,无论是软件测试还是软件V&V,均无法保证百分之百的覆盖率。因此,引入标准规范和软件开发活动属于被动防御手段,并不能完全规避C语言的不安全特性带来的安全风险。

Rust语言自问世以来,致力于成为优雅解决高并发、高安全系统问题的编程语言,适用于大型场景,创造维护能够保持大型系统完整的边界,因此更加强调安全性、内存布局控制和并发处理方面的特性,在网络服务器领域引起极大重视。核电领域因其特殊性,Rust语言应用尚处于探索阶段。本文就Rust语言应用于核电安全级仪控软件开发,以规避C语言的安全风险的可能性进行探讨。

1 C语言的缺陷

C语言是一种不安全的语言,其固有特性易使得所开发的程序存在安全缺陷,同时其极大的灵活性也容易导致开发人员的不安全使用行为,均为软件带来了安全隐患,可能导致软件失效。

1.1 指针问题

在C语言中未对指针的使用加以限制,指针理论上可以访问任意的内存空间。若访问了非法或者受保护的内存地址,则会导致内存问题,然而C语言编译器并未对指针操作进行严格的安全性检查。这带来了如下几方面的问题:

1)C语言不对空指针进行检查,空指针所指向的内存空间一般是受保护的。在软件中对空指针进行解引用,会引发软件异常。

2)C语言中不强制要求指针初始化,未初始化的指针即是野指针。野指针的值取决于以前遗留的是什么值,因此它可能指向未知的内存空间,对野指针进行解引用,可能会引发软件异常,也可能不会。但无论如何,这个行为不属于预期内的安全行为,存在安全隐患。

3)C语言使用指针访问动态申请的内存空间,当内存空间使用完毕并进行释放后,指针仍旧指向已释放的空间,此时的指针便是悬空指针。它与野指针类似,同样会操作不属于自己的内存空间,导致安全问题。图1展示了对悬空指针进行操作的情况。

1.2 内存不安全

C语言内存管理由开发人员通过内存管理函数手动进行分配和释放,C语言提供了一系列的内存管理函数(如malloc、calloc、recalloc、free等)。若使用不当,会引发内存问题。然而,C编译器在编译阶段并不能暴露此种情况,导致运行过程中出现内存错误,可能引发软件崩溃。

常见的内存问题有内存泄漏和内存释放错误。动态申请的内存使用完毕后,并未调用相应的释放函数对其进行释放,则会造成内存泄漏[3]。C语言无法暴露内存泄漏问题,内存泄漏导致可用的内存越来越少,最终引发程序崩溃,图2对此种情况进行了展示。内存的分配和释放要配对,若对一块内存空间执行重复释放,也会造成内存释放错误。若指针指向的地址并不是内存分配后的地址,对其执行释放操作,也是危险的。

图2 内存泄漏Fig.2 Memory leak

2004年以来,微软安全响应中心(MSRC)已对所有报告过的微软安全漏洞进行了分类。根据他们提供的数据,所有微软每年的补丁中约有70%是针对内存安全漏洞的修复程序,故而微软正在考虑使用新的内存安全语言替代C/C++语言进行操作系统的开发。

2 Rust语言优势

Rust语言是Mozilla主导开发的通用、编译型语言,专注于安全,尤其是并发安全[4]。设计准则为“安全、并发、实用”,支持函数式、并发式、过程式以及面向对象的编程风格。在语法上和C++类似,但是在设计上保证性能的同时需提供更好的内存安全,通过一系列的手段让不安全的内存风险在编译阶段暴露,保证了程序运行中的内存安全。

2.1 所有权

每种编程语言都有其管理使用计算机内存的方式,要么通过开发人员手动进行内存的分配和释放(如C语言),要么提供垃圾回收机制,在程序运行时不断寻找不再被使用的内存并进行释放(如Java语言)。前者将内存管理权交给了开发人员,存在人因的内存安全风险,后者会降低程序运行时性能。而Rust语言采用了一种全新的方式:通过所有权系统管理内存。Rust语言编译器在编译期间执行所有权规则检查,即可明确所有对象的作用域和生命周期,从而可以在某个对象不再被使用时将其销毁,并且不影响程序运行时性能。

Rust语言的所有权系统规定了下述的所有权规则:

1)Rust语言中每个对象都有一个所有者。

2)对象有且只有一个所有者。

3)所有者离开作用域后,其所代表的对象会被立即销毁。

4)赋值语句、函数调用等会导致所有权转移,原有所有者失去对象的所有权。

Rust语言的所有权系统保证了某一时刻只有一个变量持有对象的所有权,避免了数据竞争和重复释放。所有者离开作用域时销毁其对象的机制,也防止了内存泄露。

2.2 所有权借用

在Rust语言的所有权规则中,当某个变量被传入一个新的作用域中时,变量的所有权也从原作用域转移到新的作用域;当变量返回原作用域时,却已经丧失了原有的所有权。一个典型的例子是:某个变量作为参数传入函数,执行函数调用后,该变量会失去对象的所有权,后续无法通过该变量使用其对象,这并不符合预期。因此,Rust语言提供了所有权借用特性,非所有者的变量或者函数想要访问对象时,通过借用对象所有者的所有权以达到目的,所有权借用不造成所有权转移,借用完毕后归还所有权。借用所有权会让所有者受如下限制:

1)在不可变借用期间,所有者不能修改资源,并且也不能再进行可变借用。

2)在可变借用期间,所有者不能访问资源,并且也不能再出借所有权。

2.3 引用

Rust语言对指针的使用进行了限制,原生指针(类似C语言的指针)只能在不安全代码中进行使用,针对安全编程,Rust语言提供了一种更高级的指针语义——引用。引用与指针的差别在于:指针保存某块内存的地址,引用则可看作某块内存的别名,引用的使用要求满足Rust语言编译器各种安全检查规则。

在Rust语言的所有权系统中,引用产生所有权的借用,引用在离开作用域时归还借用的所有权。虽然使用引用与直接使用被引用者一样自然,但是受如下规则的限制,违反规则中的任何一条,编译器便会报错并给出提示。

1)在某个时刻,某个变量要么拥有一个可变引用,要么拥有多个不可变引用。

2)引用必须保证有效。

3)引用的生命周期不能超过被引用者的生命周期。

引用避免了空指针和野指针的情况,防止了数据竞争。引用的生命周期检查保证了数据不会在其引用离开其作用域之前被释放而变成悬垂状态,避免了C语言中悬空指针的问题。

3 Rust语言在核电的应用

Rust语言优于C语言的安全特性,不输于C语言的性能,以及具备嵌入式开发的能力,使其十分适合用于执行开发安全功能的嵌入式软件,结合核电仪控软件安全可靠的发展需求,使得Rust语言在核电仪控领域的应用成为可能。

3.1 安全级操作系统

目前在核电仪控领域,核电仪控软件为了满足功能安全中的确定性要求,大多采用定周期的裸机系统。随着核电仪控系统自动化、智能化发展,核电仪控软件功能日益增多,裸机系统的弊端也逐渐凸显出来。

1)传统的裸机系统按照顺序执行各功能,随着软件功能的增多,软件周期增大,导致安全相关的功能不能及时执行,无法满足安全功能的实时性要求。

2)裸机系统各功能模块存在耦合,系统功能的增多导致软件复杂性变高,可维护性变差。尽管采用安全级操作系统可避免裸机系统带来的问题,然而使用不安全的C语言开发一款安全级操作系统无疑是一项成本极高且难度极大的任务,而且C语言的不安全特性也导致其开发的操作系统的安全性受到质疑。因此,时至今日,在功能安全相关的核电仪控软件中几乎未见到操作系统的身影。

Rust语言的出现可能改变这一现状。一方面,Rust语言具有丰富的高级语言特性,如函数式编程语言的模式匹配和类型推导,基于trait的泛型机制,强大的抽象能力等,非常适合大型系统编程场景,采用Rust语言开发操作系统变得相对简单;另一方面,Rust语言提供强大的类型系统和独特的生命周期管理,实现了编译内存管理,保证内存安全和线程安全的同时,运行效率还能与C/C++保持在同一级别。

基于Rust语言开发的安全级操作系统,在成本、安全、效率等方面存在较大优势和竞争力,未来应用于核电仪控软件领域的可能性较大。一个典型的基于Rust语言的安全级操作系统如图3所示。

图3 Rust语言安全级操作系统架构Fig.3 Rust language security level operating system architecture

3.2 安全级应用开发

裸机系统中没有严格对应用程序和设备驱动程序进行隔离,整个系统核心由一个大的死循环构成,系统所有功能模块均包含在死循环内,应用程序和设备驱动程序之间存在直接或间接的功能耦合,难以实现独立安全的应用程序。

基于Rust语言开发的操作系统,使用Rust语言开发安全级应用程序变得简单。安全级操作系统实现了应用与驱动程序、应用程序与应用程序之间的安全隔离,保证了单个应用程序的安全性、独立性,也避免了单个应用程序故障导致系统失效的风险。

4 Rust语言应用于核电仪控的挑战

4.1 有限的行业应用经验

Rust语言作为一门新的编程语言,目前在核电领域的应用几乎处于空白,没有成熟的项目和成功的经验作为参考和支撑,不免令人对其应用于核电仪控领域的安全性、适用性和可靠性产生担忧。

4.2 标准的缺失

C语言在核电领域的广泛应用,配套的相关行业标准十分完善。IEC61508-7[5]的附录C4.5中对C语言用于开发功能安全系统给出了限定条件:“具有子集和编码标准和静态分析工具的C”。为了满足此条件,制定了MISRA-2004、GJB5369-2005《航天型号软件C语言安全子集》、GB/T28169-2011《嵌入式软件C语言编码规范》等一系列C语言相关标准和规范。

而Rust语言目前暂未纳入IEC61508推荐用于开发功能安全系统的系列编程语言中,因此相关的行业标准缺失,缺少相关标准进行指导和规约,其应用与核电仪控领域的竞争力被削弱。

4.3 缺少配套工具

Rust语言目前仅具备基础的编译、调试等生产工具,尚未提供用于功能安全开发活动的工具支持,如经过安全认证的开发工具、验证软件、静态解析和自动化测试工具等,作为功能安全领域软件开发活动必需的生产工具,其重要性不言而喻,使用未经认证的开发工具所开发的软件不能满足安全要求。因此,要使得Rust语言广泛应用于核电仪控领域,完善安全相关的开发工具是前提。

4.4 开发迁移

目前大部分的核电仪控软件开发采用C语言,熟悉Rust语言的开发人员较少,Rust语言应用于核电仪控领域,需要开发人员由C语言迁移到Rust语言,迁移存在几个难点:一是开发人员缺少Rust语言的开发经验,需要从头学起;二是Rust语言和C语言的语言特性差异较大,因此在软件设计和软件编码上均存在较大差异,开发人员需要编程思维的转变;三是Rust语言在市场应用方面还比较小众,可用的功能函数库及开源库较少,需要开发人员自己造轮子,对开发人员提出了更高的要求。

5 结束语

Rust语言的特性与核电仪控软件发展需求完美契合,本文对Rust语言在核电仪控软件的应用可能性进行了探讨,旨在推动Rust语言在核电仪控领域的应用发展。可以预见,随着Rust语言自身的发展,相关标准的出台以及配套工具的完善,各类相关机构和组织都将对Rust语言在核电仪控领域的应用进行积极的探索和研究,Rust语言会在核电仪控领域展现出强大的活力。

猜你喜欢
开发人员指针C语言
基于Visual Studio Code的C语言程序设计实践教学探索
Semtech发布LoRa Basics 以加速物联网应用
基于C语言的计算机软件编程
为什么表的指针都按照顺时针方向转动
高职高专院校C语言程序设计教学改革探索
基于改进Hough变换和BP网络的指针仪表识别
后悔了?教你隐藏开发人员选项
论子函数在C语言数据格式输出中的应用
ARM Cortex—MO/MO+单片机的指针变量替换方法
三星SMI扩展Java论坛 开发人员可用母语