C/C++编程安全标准GJB-8114解读——声明定义类

软件检测实验室在建立软件测试体系或申请cnas/cma相关资质时,需要依据相关标准,使用有效的方法开展检验检测活动,GJB-8114是一部嵌入式软件安全测试相关的国家标准,本系列文章我们就针对GJB-8114《C/C++语言编程安全子集》的具体内容进行分析解读。

GJB-8114标准规则中一共有124条强制性规则,是按类分的,一共有13类,声明定义类、版面书写类、指针使用类、分支控制类、跳转控制类、运算处理类、函数调用类、语句使用类、循环控制类、类型转换类、初始化类、比较判断类以及名称、符号与变量使用类。本文我们先针对声明定义类进行解读。

声明定义类一共有23条,都是我们在日常的工作中写程序的时候容易出的一些瑕疵,不能说是错误,但是在规则里是不被允许的。很多人可能会说,它并不影响程序的实际运行,这样理解是片面的。所有这些规则都是航天型号软件在整个发展过程中出现的一些问题,经过总结归纳而来的。

R-1-1-1禁止通过宏定义改变关键字和基本类型含义


大家用过C语言的都知道,像字符类型定义等都被称为关键字,这些关键字通常不能把它当作一个基本类型,重新定义。

R-1-1-2禁止将其他标识宏定义为关键字和基本类型


比如说把一个int64定义成长整型,这就是违反规则的,标准的定义应该是把一个长整型定义成int64。

R-1-1-3用typedef自定义的类型禁止被重新定义


比如说我们把一个int的类型定义成了mytype,就不能再把一个float型或其他类型定义成mytype了。

R-1-1-4禁止重新定义C或C++关键字


本来在标准的C语言中是不支持重新定义的,但是在C++语言中支持重定义。实际上在大家在编写程序的过程中会发现,在C++中重新定义关键字是没有任何问题的,只不过咱们的GJB-8114规定不允许这样定义。

R-1-1-5禁止#define被重复定义


用#define定义一个宏,然后再定义这个宏为别的,这样就是重复定义,原则上是不允许的。在C语言以及C++语言现在的各个编译器中这样定义并不会出错,但是会出现一个问题,当你用到这个被定义的宏的时候,就会困惑,这个宏到底用的是哪一次定义的值?原则上是离它最近的那次定义的值,但是分不清。所以想重新定义这个宏的话,要用一个undef取消定义后再重新定义。

R-1-1-6函数中的#define和#undef必须配对使用


原则上来说是不允许单独使用#undef这个关键字的,大家可以根据上面举的这些例子看一下。实际上这些在预编译过程中就可以发现定义得是否正确,比如说示例2中的例子,#ifdef、 #undef,如果你不用#endif的话是通不过的。但是在早期的编译器中是不太容易发现的,所以这条规则也被提了出来。

R-1-1-7以函数形式定义的宏,参数和结果必须用括号括起来


比如说违背示例中展示的,我们定义了两个参数,这两个参数我们没有把它括起来,或者我们定义了一个参数,我们也没有将它括起来。这样会出现什么问题呢?在咱们的编译器中,是先把这个宏进行解析,替代。也就是用你定义的这个宏替代你写的表达式中相应的宏引用。

当你不用括号的时候,比如说你存的这个参数是一个表达式,这个表达式不是先计算一个,就会出现问题。通常大家可能也不太注意,这样用的时候,程序可能也没错,是因为你存参数的时候没有用表达式,当你用表达式的时候就会出问题了。

R-1-1-8结构、联合、枚举的定义必须定义标识名


比如像违背示例所示,我们定义一个结构,把这个结构体取了一个变量名。但是在早期,基本上都是这样做的。这种方式定义的结果是什么呢?对程序没有任何影响。但是按照现在的要求,这样做是不可以的,一定要把这个结构取一个名字,然后在后边声明这个结构为哪个变量。

结构、联合、枚举都是这样要求的,像违背示例中展示的例子,实际上你在程序中这样做了它也不会出问题,只不过你用遵循示例这样的结构重新声明一个变量的时候,就会出问题了。

R-1-1-9结构体定义中禁止含有无名结构体


在一个结构体中又包含一个结构体,里面这个结构体一定要有一个对应的变量名,这样你才能够引用这个结构体中的元素,如果没有变量名的话就不能引用这个元素。像违背示例中展示的,比如说我要用到这里的xs,它是哪一个元素下面对应的元素呢?遵循示例中就告诉你,它是Scoor结构元素下对应的一个元素。

R-1-1-10位定义的有符号整型变量位长必须大于1


由于符号位至少要占有1位,所以定义一个有符号的位变量的时候,至少要达到2位才能表示有符号的位变量是整的还是负的。

R-1-1-11位定义的整数型变量必须明确定义是有符号还是无符号


违背示例中所展示的定义方式,原则上来说是没有什么问题的,编译器并不会显示这是一个错误。但是为了明确表达这个数有没有负的可能性,所以说一定要在前面标识出,这个数是整型的,是带符号的,还是不带符号的。这是一个强制性要求,在程序中大多数情况不会出错,只有在极少数的情况下会出错。所以说,一般的情况下还是要按照这种规则定义一下。

R-1-1-12位定义的变量必须是同长度的类型且定义位禁止跨越类型的长度


比如说像违背示例中,定义了很多的串。不能跨越类型也就是说,一个定义不能由两个串(单位)组成。与此同时,不能定义一个位变量既在第一个八位当中,同时在其它八位中也含有它的一些位,也就是说不能跨一个字符。

R-1-1-13函数声明中必须对参数类型进行声明,并带有变量名


违背示例中所举的例子,在最早的C语言中是标准的定义,但是现在要求,凡是不带参数的要写上void,带参数的不能光写它的类型,同时要有一个它的名字。通常我们在写函数体中是肯定带这个名字的,但是在函数声明中,有些人为了简略,或者有些年龄比较大的人,学C语言比较早的人就会容易不带变量名去写声明。
这个在编译器里是直接通过的,没有任何问题,但是要求不允许这样做。这样做会引起什么后果呢?可以很负责任地说不会引起什么后果,这就是一个强制性的规则。

R-1-1-14函数声明必须与函数原型一致;一致性要求包括函数类型,参数类型和参数名


这个在我们的实际操作过程中,往往是先写了一个标准的函数,然后把函数定义的部分直接就复制到函数声明中去,这样就不会引起错误。但是有些人是先构造了一些函数,再具体写这些函数实现,这样往往就会导致函数的参数名前后不一致了。

比如违背示例中展示的,在实现中,用了一个length、一个width,但是在声明中声明了一个length一个b。实际上这个编译也不会有任何问题,但是要求是不允许的。同时这个例子中,它的声明和定义就不是一个函数,如果在写程序的过程中,如果出现这种情况,就会发现,链接提示找不到那个函数,它俩并不被认为是一个函数。

R-1-1-15函数中的参数必须使用类型声明


也就是说参数必须有一个类型,如果没有类型的话,实际上编译器是无法通过的。在咱们介绍的这么多规则当中,有一些实际上你想这么做都做不到,因为只要你这样做了,编译器就通不过,所以这些规则在以后的GJB-8114的修订过程中,就有可能就会把这些规则给废掉了,但是目前没有这种打算,这种规则依旧存在。

R-1-1-16外部声明的变量,类型必须与定义一致


这个也就是说你声明了一个外部的变量,它定义的类型在重新声明外部变量的时候,类型还必须是一致的。如果你的声明不一致,有些编译器检查得不太严格,也不会出问题,但是当你用的时候,就会发觉一些问题。比如说你用一个整型的,重新声明的时候声明为了长整型。
当然现在在PC机上,整型和长整型都是4个字节的,应该不会出什么问题,但是原来这种整型是2个字节,16位,长整型是4个字节,32位。当你用到重新声明中的长整型时,你对它进行赋值,赋的是32位,可你只占了16位的地址,就会把这个变量后面的地址中后面的16位也给赋值了,就会改写你的程序。有时候你还发现不了,这个是一个挺严重的错误。

R-1-1-17禁止在函数体内使用外部声明


这个是说我在一个函数体内声明外部的变量、函数,这个在大多数的编译器中都不会出问题,都能够通过,但是上原则上是不允许的,要像遵循示例中表示的那样,把这些外部声明专门放到函数体的外面。比遵循示例中更好的方式是,放到一个头文件中,在前面有一个#include头文件。

如果你总是按照违背示例中那样写的话,就会发现整个程序会很乱,不易于阅读,而且它对于一个函数的总行数也有很大的影响。

R-1-1-18数组定义禁止没有显式的边界限定


通常的时候我们做数组定义的时候,并不知道要定义多长,就不写我这个边界到底是多大,有多大就自动做成多大。在我们学习C语言或者C++语言的时候这种定义没有任何错误,实际上它是符合C语言的语法的,只不过是不符合GJB-8114的规则。

所以说有时候当我们把程序交给测评机构进行测评的时候,他们会发现违反了很多的规则,给你列出来都有哪些。你一看会觉得,我学的时候都是这样学的呀。实际上语法就是这样,可能你的语法是没问题的,但是却是违反规则的。

就是说必须显式地定义它的长度,不依靠机器或者编译器给它分配长度。但是这里面有一个例外,大家看看遵循示例中举的例子,比如说我们定义指针的数组,就可以定义成两个指向字符串指针的地址。显然没有对每一个字符串的长度没有做限定,对字符串的个数做了限定。
为什么支持这样的呢,我们原来好多做页面的时候要做菜单,菜单最好是这么定义,不能限定死了,尤其是我们还涉及到一些指针的动态分配,所以说这种情况是被允许的。当然我们现在很少有直接写菜单的了,所以严格来说,这样写也不是非常合适的,这里就是我们GJB-8114的举例中有些矛盾的地方。

R-1-1-19禁止使用extern 声明对变量初始化


一个变量初始化可以在声明中进行初始化,但是不允许在外部声明的时候对它进行初始化。也就是说不管在我声明的时候有没有初始化,但是在外部声明的时候都不能做初始化。

R-1-1-20用于数值计算的字符型(短型)变量必须明确定义是有符号还是无符号


在示例中,char是一个标准的类型定义,但是在我们的GJB-8114规则中规定。不允许char这种类型,只能有 unsigned的char或者signed的char。这样可以帮助大家通俗地理解char这个类型是存正数或者存正负数。

R-1-1-21禁止在#include 语句中使用绝对路径


这个一般老的程序员不会犯这种错误,新程序员挺容易犯这种错误的,在写路径的时候就直接指明了是什么目录,就像违背示例中展示的那样,实际上是不允许的。像遵循示例中那样写,好处是什么呢?像违背示例,比如说你的程序,在C盘上运行,可以寻找C盘的目录,如果在D盘上运行,它仍然要找C盘的目录。而遵循示例,会去找当前目录,也就是说我在哪运行就找哪个目录下的东西。所以,考虑到可移植性、可运行性等,禁止用绝对路径来表示。

R-1-1-22禁止头文件重复包含


像违背示例中展示的例子,对文件1做了定义,在文件2中包含了文件1,在实际用的时候,即包含了文件1,也包含了文件2,这样就是重复包含了。这种重复包含往往不容易发现,那怎么办呢?

对于头文件定义.h文件的写法有一个通常的写法,像遵循示例中展示的那样,如果没有定义头文件,我就把头文件定义一下,把内容写进去,在最后用个#endif。文件2中既包含了文件1,又包含了文件2,当我遇到文件2的时候,对它进行解析,发现文件1已经被定义了,直接就到最后了,就不会出现重复包含。
如果大家在头文件中定义的是一些变量,大家会发现在编译器中,违背示例那样是通不过了,如果没有定义变量,只是定了一些宏,那是可以通过的。

R-1-1-23函数参数表为空时,必须使用void 明确说明


以前我们学习C语言的时候,可能老师会说括号里面没有参数,可以不写参数直接用括号来代替了,现在规定,括号里面如果没有参数,必须用一个void 来说明,比如说你这个函数不希望它返回参数,也需要用void作为它的类型声明。实际上违反它并不会使程序出错,但是它是违反我们强制性规则的。

后面的文章会继续针对其他大类为大家展开介绍,欢迎继续关注。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/36161.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android 热修复一

一、什么是热修复? 在我们应用上线后出现bug需要及时修复时,不用再发新的安装包,只需要发布补丁包,在客户无感知下修复掉bug。 实现效果: Demo源码: https://gitee.com/sziitjim/hotfix 二、怎么进行热修…

一文了解Docker之网络模型

目录 1.Docker网络 1.1 Docker网络模型概述 1.2 Docker网络驱动程序 1.2.1 host模式 1.2.2 bridge模式 1.2.3 container模式 1.2.4 none模式 1.3 Docker网络命令示例 1.3.1 创建一个自定义网络 1.3.2 列出所有网络 1.3.3 连接容器到网络 1.3.4 断开容器与网络的连接…

如何与ChatGPT愉快地聊天

原文链接:https://mp.weixin.qq.com/s/ui-O4CnT_W51_zqW4krtcQ 人工智能的发展已经走到了一个新的阶段,在这个阶段,人工智能可以像人一样与我们进行深度的文本交互。其中,OpenAI的ChatGPT是一个具有代表性的模型。然而&#xff0…

【ARM Coresight 系列文章 3.1 - ARM Coresight DP 对 AP 的访问 1】

文章目录 1.1 DP 中相关寄存器的介绍1.1.1 DPACC and APACC 寄存器1.1.2 DP SELECT 寄存器1.1.3 AP CSW寄存器1.1.4 AP TAR 寄存器1.1.5 AP DRW寄存器1.1.6 AP Banked Data registers 1.1 DP 中相关寄存器的介绍 如果DAP接入的是JTAG接口,那么将会通过APACC寄存器来…

[VUE学习]权限管理系统前端vue实现8-右上角用户头像显示实现

1.现在有个问题 我们再没有token情况下通过url可以直接访问页面 这不可以 所以我们需要添加路由守卫 拦截 2.permission.js的代码 import router from "/router/index" import store from "/store"router.beforeEach((to,from,next)>{const whiteList…

React类组件

1. React组件 将页面按照界面功能进行拆分,每一块界面都拥有自己的独立逻辑,这样可以提高项目代码的可维护性。其中React组件分为两种,一种是类式组件,一种是函数式组件。这里我们将的是比较常用的类式组件,但是在后续…

括号生成(力扣)递归 JAVA

目录 题目描述:纯递归解法:递归 回溯: 题目描述: 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 示例 1: 输入:n 3 输出&#xff1a…

子集 (力扣)数学推理 JAVA

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1: 输入:nums [1,2,3] 输出:[[],[1],[2],[1,2],[3],[…

Unity/Shader 零碎知识点

坐标系 Unity使用的是左手坐标系&#xff1b;观察空间&#xff0c;通俗来讲就是以摄像机为原点的坐标系&#xff0c;摄像机的前向是z轴的负方向&#xff0c;与模型和世界空间中的定义相反&#xff0c;z轴的坐标减少意味着场景深度的增加 点积 abba|a||b|cos<a,b> 结果为常…

邮票面值-2022年全国青少年信息素养大赛Python国赛第5题

[导读]&#xff1a;超平老师计划推出《全国青少年信息素养大赛Python编程真题解析》50讲&#xff0c;这是超平老师解读Python编程挑战赛真题系列的第7讲。 全国青少年信息素养大赛&#xff08;原全国青少年电子信息智能创新大赛&#xff09;是“世界机器人大会青少年机器人设计…

Spring Boot原理分析 | SpringApplication、Yaml、Properties

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Spring Boot Spring开源框架&#xff0c;轻量级的Java开发框架&#xff0c;解决企业级应用开发的复杂性而创建&#xff0c;简化开发 基于POJO的轻量级和最小侵入型编程…

Kafka入门,漏消费和重复消费, 消费者事务,数据积压(二十四)

漏消费和重复消费 重复消费&#xff1a;已经消费了数据&#xff0c;但是offset没提交。 漏消费&#xff1a;先提交offset后消费&#xff0c;有可能会造成数据得漏消费 消费者事务 如果向完成consumer端得进准一次性消费&#xff0c;那么需要Kafka消费端将消费过程和提交offs…

【Accumulate】Gitee解决每次推送输入账户密码问题

【前言】 每次建立私人仓库后&#xff0c;一推送就得输入账户密码&#xff0c;真的巨烦人啊。 【解决】 step1&#xff1a; 绑定私匙&#xff1a; 配置Git_犟小孩的博客-CSDN博客 step2&#xff1a; 每次绑定远程仓库的时候&#xff0c;使用SSH绑定 如果已经绑定过了&…

YoloV2

时间线 Motivation Yolo-v1是在检测精度尚可的前提下达到了实时检测&#xff0c;同年的SSD检测速度略慢但检测精度远高于Yolo-v1&#xff0c;因此&#xff0c;Yolo-v2则是着眼于检测得更快更准&#xff0c;同时它利用WordTree创造性地将Imag…

回归预测 | MATLAB实现WOA-DBN鲸鱼算法优化深度置信网络的多输入回归预测

回归预测 | MATLAB实现WOA-DBN鲸鱼算法优化深度置信网络的多输入回归预测 目录 回归预测 | MATLAB实现WOA-DBN鲸鱼算法优化深度置信网络的多输入回归预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 基于鲸鱼算法优化深度置信网络(WOA-DBN)的数据回归预测&…

vim的使用方法及相关按键

目录 一、安装vim 二、vim的使用 1.打开vim 2.vim的四种模式使用 &#xff08;1&#xff09;命令模式&#xff08;快捷键的使用&#xff09; &#xff08;2&#xff09;编辑模式 &#xff08;3&#xff09;末行模式 &#xff08;4&#xff09;可视化模式 一、安装vim …

虹科方案 | Redis Enterprise:适用于任何企业的矢量数据库解决方案

用户希望他们遇到的每个应用程序和网站都具有搜索功能。然而&#xff0c;超过80%的业务数据是非结构化的&#xff0c;以文本、图像、音频、视频或其他格式存储。因此&#xff0c;我们需要一种跨非结构化数据的搜索方式。 什么是矢量数据库&#xff08;vector database&#xff…

基于深度学习的高精度老虎检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度老虎检测识别系统可用于日常生活中或野外来检测与定位老虎目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的老虎目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型…

uniapp学习之【uniapp的返回事件 onBackPress 在微信小程序中不生效的问题】

uniapp 的返回事件 onBackPress 在微信小程序中不生效的问题 场景&#xff1a;页面中点击左上角的返回按钮,监听返回操作,页面返回前执行了一些操作, uniapp 页面生命周期中有 onBackPress ,因此将操作写在了 onBackPress () 页面生命周期钩子当中, H5 测试一切正常,但是微信开…

集合面试题--LinkedList数组

目录 单向链表 介绍 时间复杂度分析 双向链表 时间复杂度分析 总结 ArrayList和LinkedList的区别是什么&#xff1f; 单向链表 介绍 时间复杂度分析 双向链表 时间复杂度分析 总结 ArrayList和LinkedList的区别是什么&#xff1f;