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

news2024/9/21 20:30:22

软件检测实验室在建立软件测试体系或申请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作为它的类型声明。实际上违反它并不会使程序出错,但是它是违反我们强制性规则的。

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

js逆向-md5加密算法逆向-案例网站

今天逆向的网站:aHR0cHM6Ly9mYW55aS55b3VkYW8uY29tL2luZGV4Lmh0bWwjLw (去在线网站进行base64解密即可) 1、点击翻译,触发请求 可以看到sign参数加密,加密长度为32为 md5加密特征: **长度固定。**无论输…

基于树莓派4B的YOLOv5-Lite目标检测的移植与部署(含训练教程)

前言:本文为手把手教学树莓派4B项目——YOLOv5-Lite目标检测,本次项目采用树莓派4B(Cortex-A72)作为核心 CPU 进行部署。该篇博客算是深度学习理论的初步实战,选择的网络模型为 YOLOv5 模型的变种 YOLOv5-Lite 模型。Y…

记一次解决vmware安装windows server 2019时, 虚拟机网络电缆被拔出,连不上网的问题

项目场景: 项目需要基于electron开发桌面端软件,实现前后端项目的自动化部署、可视化配置等功能,经过需求分析后,确定首先要适配的场景即:通过桌面端软件远程连接,在桌面端软件中执行安装、运行、配置等一…

用ZLmediaKit流媒体服务器时候遇到的常规问题

照zlmediakit的源码 自己复制了一份 然后有的地方编译不过修改了部分 测试的时候发现有两个问题 第一是 ffmpeg的ffplay 能播放 vlc不能播放 第二个问题是directProxy设置为0的时候 推流的时候 然后用ffplay播放 只有音频没有视频 查了好久终于解决这个问题 第一个…

Verilog/C++实现排序算法

Verilog/C实现排序算法 1、冒泡排序算法 冒泡排序是一种简单的交换类排序。 冒泡排序算法的原理如下: 1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。2、对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一…

深入解析Spring Boot:构建现代化Java应用程序的利器

深入解析Spring Boot:构建现代化Java应用程序的利器 文章目录 导言1. 简化的开发流程2. 内嵌的Web服务器3. 自动配置4. 健康检查和监控5. 外部化配置6. 强大的生态系统小结 导言 Spring Boot 是一个开源的Java框架,旨在简化和加速Java应用程序的开发过程…

关于CSPM国标证书(项目管理专业人员能力评价)

先来回答一下粉丝提问: 1、软考高项可以对标吗? 答案:软考高项是不可以对标的。 2、Prince2可以对应哪一个级别? 答案:哪一个级别都不可以对标,目前可对标的是PMI,IPMA、HCSE-PM(华…

代码随想录二刷day35 |贪心 之 860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球

day35 860.柠檬水找零406.根据身高重建队列452. 用最少数量的箭引爆气球 860.柠檬水找零 题目链接 解题思路: 局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。 代码如下&#xff1a…

NodeJS NVM版本管理⑩⑧

文章目录 ✨文章有误请指正,如果觉得对你有用,请点三连一波,蟹蟹支持😘前言 N V M I n t r o d u c e NVM Introduce NVMIntroduce N V M U s e NVMUse NVMUse D o w n l o a d A n d I n s t a l l Download And Install Downloa…

DTC143ZM理解介绍(含电路应用)

前人种树,后人乘凉;创造不易,请勿迁移~ author daisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 daisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主daisy.skye擅长嵌入式,Qt,Linux,等方面的知识https://blog.csdn.net/qq_40715266?t…

C语言sin函数学习

函数名: sin 头文件&#xff1a;<math.h> 函数原型: double sin(double x); 功 能: 正弦函数 参 数&#xff1a; double x 操作的弧度 返回值&#xff1a; 返回弧度的正弦值 1π/180弧度 这是C标准库的定义&#xff1b; #include<stdio.h>#include<mat…

普乐蛙VR太空宇宙vr星际飞船设备模拟太空飞船

科技感十足!你有没有想过自己能够亲身体验到太空飞行的感觉?这一刻&#xff0c;梦想成真! 宇航员体验 VR科技让人类走进了未知领域&#xff0c;现在&#xff0c;你可以在舒适的空间内感受宇宙中的万千风景&#xff0c;体验宇航员的工作和生活。而这次VR科技体验馆更是为你准备…

uni-easyinput连续输入出现闪动解决

原因分析&#xff1a; 是因为uni-easyinput源码中&#xff0c;在输入触发事件中一直去同步modelValue&#xff0c;而modelValue其实就是双向绑定的值&#xff08;有一定延迟&#xff09;&#xff0c;当连续输入时&#xff0c;会导致input和modelValue不一致&#xff0c;就会出…

YOLOv8遇见VisDrone 2023目标检测挑战赛-YOLOv8实战VisDrone无人机目标检测(视频教程)

课程链接&#xff1a;https://edu.csdn.net/course/detail/38688 VisDrone 2023目标检测挑战赛( http://aiskyeye.com/challenge-2023/)和 ICCV 2023 顶会联合举行&#xff0c;用于检测从无人机获取的视觉数据中的物体。优胜者可出席 ICCV 2023 研讨会&#xff0c;并获得万元奖…

如何利用python做爬虫?

Python爬虫在许多情况下是非常有用的&#xff0c;爬虫可以帮助自动化地从互联网上获取大量数据。这些数据可以是产品信息、新闻文章、社交媒体内容、股票数据等通过爬虫可以减少人工收集和整理数据的工作量&#xff0c;提高效率。在软件开发中&#xff0c;可以使用爬虫来进行自…

为什么学习STM32相对困难?如何优化学习过程?

当你在学习STM32时感到困惑&#xff0c;可以考虑以下优化策略&#xff1a;理解基础概念&#xff1a;确保你对STM32的基础概念有清晰的理解&#xff0c;包括芯片架构、寄存器配置和外设功能等。通过仔细阅读官方文档、参考手册或教程&#xff0c;加深对这些概念的理解。我这里有…

Android Jetpack Compose之OutlinedButton的使用

Android Jetpack Compose是一个现代化的UI工具包&#xff0c;它让开发者可以更方便地构建出美观且功能强大的Android应用。本文将详细介绍其中的一个重要组件——OutlinedButton。 一. OutlinedButton简介 二. 如何使用OutlinedButton 三. 自定义OutlinedButton 四. Outlin…

两段代码共存于一个文件,编译时有选择的编译其中的一部分,有几种方法实现?如何实现?(笔试题)

两段代码共存于一个文件&#xff0c;编译时有选择的编译其中的一部分&#xff0c;请问有几种方法实现&#xff1f;如何实现&#xff1f; 1. 条件编译 使用预处理指令来控制代码的编译。通过在代码中添加条件编译指令&#xff0c;可以根据条件选择性地编译代码。条件编译指令通…

【每天40分钟,我们一起用50天刷完 (剑指Offer)】第八天 8/50

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

chatgpt赋能python:Python获取句柄的方法——在Windows平台上实现窗口控制

Python获取句柄的方法——在Windows平台上实现窗口控制 句柄&#xff08;Handle&#xff09;是Windows系统中非常重要的概念&#xff0c;它是一种指向资源对象的引用&#xff0c;以数字的形式来表示。在Windows上&#xff0c;所有资源对象都具有独特的句柄。窗口也是一种资源对…