zhanzr21的个人空间 https://bbs.21ic.com/?1195922 [收藏] [复制] [RSS]

日志

[翻译贴]从JSF C++规范来看C++与功能安全编程 ...

热度 1已有 307 次阅读2018-1-25 17:10 |系统分类:兴趣爱好

目前而言,谈到安全编程主要是C语言编程. 但是随着程序的复杂性日益增长,C++越来越多的被应用在汽车电子,航空航天等领域. 比如F-35战斗机就大规模应用了C++,使得开发过程与成本都得到了大大的优化. 可以预见C++在今后的安全编程领域将得到越来越广泛与深入的应用. F-35的开发者发布了JSF C++编程规范, MISRA也推出了C++的相应标准MISRA C++ 2008. 这两者有相互兼容也有一些差异. 比如JSF C++不允许使用C++的异常(主要跟当时开发工具对异常支持较差相关), 而MISRA C++则对使用C++异常做了一些详细的规定, 事实上就是对可控的使用持肯定态度.

在功能安全领域使用C++的优点:
1.更加高的抽象等级. C++在抽象等级上相对于C语言更加上升了一层楼,使得开发更加复杂的应用时更加得心应手. 而且在此基础上, 允许手工优化和与硬件紧密结合的特性依旧被保留.
2.支持面向对象编程. 这个是软件工程发展的大的趋势,尤其是在嵌入式领域, 面向对象概念尤为重要.
3.可移植性.这一点继承自C语言,但是有很多比较现代的算法需要C++才能完成,所以相对于C语言,可移植性更进一步.
4.性能优势. 随着编译器技术的发展,C++工具已经在很多领域能生成比C语言更加高效的代码.
5.人才优势. 软件人才中, C++程序员非常多.
6.工具支持.目前很多基于模型编程的代码生成工具都可以自动生成C++代码.
7.成熟度. C++经过发展多年,已经趋于成熟且经过了业界的各种实践考验.

当然C++也有自己的一些局限:
1.C++的复杂度决定了掌握此门语言需要更加多的学习时间投入. 同时C++代码有时不够直观, 复杂的C++代码会增加bug引入的机会.
2.C++允许程序员犯很多难以被编译器察觉的错误.(常见的将'=='误写为'=').这一点也继承自C语言.
3.C++从语言层面上没有提供运行时检测的方法, 比如算术溢出或者数组访问越界. 这一点也继承自C语言.
4.虽然属于强类型语言, C++同时又留下了很多空隙给程序员绕过. 其中有些空隙是故意保持与C语言兼容性而设定.

使用C++对安全系统编程时, 必须保持对语言中会引起非预料性结果的部分的警惕. C语言这方面的问题也不少, 但是也没有阻止C语言迈向当前最普遍使用的安全编程语言的地位. 使用编程规范来约束程序员是目前比较通行与有效的方法.

比如刚刚提到的JSF C++和MISRA C++. 其中JSF C++有221条规范. 本文主要以JSF C++编程规范(以下如不特别修饰则编程规范均指JSF C++规范)为例对这些约束进行讨论.

预处理定义
各种编程规范都不怎么禧欢预处理定义. 简单而言, 只有那种防止重复包含的预处理定义被允许.如:
#ifndef        __CWND_INCLUDED__
#define        __CWND_INCLUDED__
....
#endif        // !__CWND_INCLUDED__
有些工具还支持一些其他的方式来防止重复包含,如:
#pragma once
但是这种方式就更加不标准了,当然也是JSF C++与MISRA C++不允许的做法.
预处理定义的另一大应用领域就是宏定义,比如:
#define _CRTDBG_CHECK_EVERY_16_DF   0x00100000  /* check heap every 16 heap ops */
#define _CRTDBG_CHECK_EVERY_128_DF  0x00800000  /* check heap every 128 heap ops */
#define _CRTDBG_CHECK_EVERY_1024_DF 0x04000000  /* check heap every 1024 heap ops */
还有:
#define        WND_MESSAGE_END() \
        default: break; }\
        return        ::DefWindowProc( hWnd, msg, wParam, lParam );\
        }
这两种用法在JSF C++规范是被禁止使用的. 对于常量宏定义, C++提供了更好的const关键字或者枚举. 至于代码段宏定义则有更好的替代品:inline函数.
 
由实现定义,未指定与未知行为
C++标准对几乎所有的语言元素都进行了精确定义, 但是不是全部. 还有三种语言元素的行为没有被精确定义:
由实现定义,未指定与未知行为.

由实现定义
意思是编译器的作者可以按照他认为合理的方式来制定该语言元素的最终行为, 但是必须一致,详细文档化且不能妨碍成功编译. 标准有时会列出几种处理方式供编译器的作者选择, 没有提供选择的地方完全由编译器作者来发挥.

未指定
与上面的类似,但是实现的细节不用文档化,甚至不需要保持一致.

未知行为
意为标准对该语言元素的行为不做任何要求. 遇到这种地方编译器甚至允许编译失败, 或者不加报警地生成错误代码. MISRA C++将此种情况指定为无法确定, 表明该处代码的行为将因为C++标准未作规定而无法确定其后果.

用户的代码不允许依赖上述三种情况. 如果边写编译器的扩展,也不允许依赖于上述三种情况.

容易出错的语言元素
C++标准数处规定很容易导致错误的代码. 比如switch语句, 此处JSF C++规定任意非空case后必须带上break或者throw语句以结束该case, default也不例外. if, else, switch, which, for与do语句后必须用是一个复合语句(用{}包起来),唯一的例外是if后立即带一个if. 所有的if....else构造必须以else结束. 不允许:
else
    ;
这种写法. 对于循环,也有数条规定进行约束. goto使用被严格限定, setjmp/longjmp则直接禁止使用.

类型系统
C++中的类型系统有很多漏洞可被程序员绕过. 编程规范严格限定使用隐式或者显式的转换(cast), 因为这样会导致信息的丢失. C++标准没有定义内建类型的大小,使得写出可移植性的需要固定长度整数的代码便得很困难. 另外C++(还有C语言)对整数运算时需要将操作数转换为int或者long. 这样做的结果很容易导致不可移植代码,比如:
short i = 10000;
short j = 8;
int32 result = i * j;
在int是32bit,short是16bit的平台上,结果是80000. 但是如果int为16bit的平台上这段运算的结果将为未知数,因为乘数与被乘数都会先被转为int(16bit),这样会导致溢出, 而最终的结果转换为int32之前已经是错误的结果了.
[译注: 所以应该坚决不使用不包含长度信息的数据类型, 应该使用<cstdint>中的int32_t, int16_t这种类型]. char类型也容易出幺蛾子,因为有可能是signed也有可能是unsigned的. 编程规范只允许char存放字符信息而不允许char类型的变量参与运算.

编程规范对封装很强调, 指出类的成员变量尽可能都为private, 以防止任何使用对象的指针来直接访问该成员. 除了使用纯虚函数的接口类之外, 不允许使用多继承. 对于编译器生成的默认构造函数与赋值运算符要格外留意.

动态内存
在安全系统中, 一般杜绝使用堆上的内存(malloc, free, new, delete等等). 与之类似的智能指针等概念也因此在安全系统中很罕见.

MISRA-C++规范与JSF C++规范的比较
两者都脱胎于MISRA-C, 都从MISRA-C规范中直接继承了不少条款. 在使用预处理定义上两者的观点一致反对使用除了防止重复包含的预处理语句之外的任何其他预处理定义, 而同时防止重复包含的预处理定义又被规定为必须项目. 两者都需要使用防御性编程技巧(即运行时检查),推荐使用静态分析工具. 大体来讲一些常识性的原则(命名, 定义变量需初始化)上两者保持一致.

MISRA C++对代码风格与代码的一些长度控制尚无特别条款. 在简介部分,MISRA C++的作者建议找一个合理的代码风格规范予以采用. 而JSF C++则对代码风格与代码长度控制上作了明确的规定. MISRA-C++与JSF C++两者对于一些问题上存在分歧. 比如JSF C++不允许使用C++异常, 而MISRA C++允许使用. 对于空指针, MISRA C++规定使用NULL, 而JSF C++则不建议使用NULL而直接使用0. [译注:从C++11开始, nullptr是个更好的选项].

C++编程中与功能安全相关的几个重要概念与技巧
RAII(Resource Acquisition Is Initialization), 这个不好翻译. 感兴趣的读者可自行搜索研究.

使用模板可以提高C++代码的健壮性, 因为可以实现数组的边界检查. 模板在安全编程中的一大应用为定点运算的实现.

当使用异常时, C++程序员必须对异常的安全性有深刻了解. 异常可以大大简化错误处理代码的编写. 但是不恰当使用的异常很容易使得对象或者结构体处于无效状态, 进而引发其他问题. 上文提到的RAII是设计异常安全代码的一个关键工具.

路过

鸡蛋

鲜花

握手

雷人

发表评论 评论 (1 个评论)

回复 daily媛媛 2019-1-15 18:06
最近想了解一些关于c#或者是VB方面的知识点,有没有哪位大神可以指点下,谢谢!!!