安全规则集合
重磅!《安全规则集合》正式发布 https://mp.weixin.qq.com/s/_AX2dOte7QKMYQg3UjN4bQ
safe-rules/c-cpp-rules.md at main · Qihoo360/safe-rules https://github.com/Qihoo360/safe-rules/blob/main/c-cpp-rules.md
C/C++安全规则集合
Bjarne Stroustrup: “C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off.”
针对C、C++语言,本文收录了409种需要重点关注的问题,可为制定编程规范提供依据,也可为代码审计以及相关培训提供指导意见,适用于桌面、服务端以及嵌入式等软件系统。
每个问题对应一条规则,每条规则可直接作为规范条款或审计检查点,本文是适用于不同应用场景的规则集合,读者可根据自身需求从中选取某个子集作为规范或审计依据,从而提高软件产品的安全性。
规则说明
规则按如下主题分为15个类别:
- Security:敏感数据保护、攻击防御等问题
- Resource:资源分配、使用与回收
- Precompile:预处理指令、宏、注释等问题
- Global:全局及命名空间作用域相关问题
- Type:类型相关的设计与实现
- Declaration:声明
- Exception:异常
- Function:函数实现
- Control:流程控制
- Expression:表达式
- Literal:常量
- Cast:类型转换
- Buffer:缓冲区
- Pointer:指针
- Style:样式、风格等问题
每条规则包括:
- 编号:规则在本文中的章节编号,以“R”开头,称为Section-ID
- 名称:用简练的短语描述违反规则的状况,以“ID_”开头,称为Fault-ID
- 标题:规则的定义
- 说明:规则设立的原因、示例、违反规则的后果、改进建议、参照依据、参考资料等内容
当代码出现违反规则的情况时,可分为:
- Error:可直接导致错误的问题
- Warning:可导致错误或存在隐患的问题
- Suspicious:代码的可疑形式
- Suggestion:对提高代码质量的建议
规则的说明包含:
- 示例:规则相关的示例代码,指明符合规则(Compliant)的和违反规则(Non-compliant)的情况
- 相关:与当前规则有相关性的规则,可作为扩展阅读的线索
- 依据:规则依照的ISO/IEC标准,C规则以ISO/IEC 9899:2011为主,C++规则以ISO/IEC 14882:2011为主
- 配置:某些规则的对象可由用户指定,审计工具可以此为参照实现定制化功能
- 参考:规则参考的其他规范条款,如C++ Core Guidelines、MISRA、CWE、SEI CERT等,也可作为扩展阅读的线索
规则的相关性分为:
- 特化:设规则A的特殊情况需要由规则B阐明,称规则B是规则A的特化
- 泛化:与特化相反,称规则A是规则B的泛化
- 相交:设两个规则针对不同的问题,但在内容上有一定的交集,称这两个规则相交
规则以“标准名称:版本 章节编号(段落编号)-性质
”的格式引用标准,如“ISO/IEC 14882:2011 5.6(4)-undefined
”,表示引用C++11标准的第5章第6节第4段说明的具有undefined性质的问题。
其中“性质”分为:
- undefined:一般指某种错误,使程序产生undefined behavior
- unspecified:标准不作明确规定的情况,由编译器或环境自主定义,具有随意性
- implementation defined:由实现定义,也是由编译器或环境自主定义,与unspecified不同,要求有明确的文档支持
- deprecated:已过时或已废弃的用法
本文以ISO/IEC 9899:2011以及ISO/IEC 14882:2011为主要依据,兼顾C18、C++17以及历史标准,没有特殊说明的规则同时适用于C语言和C++语言,只适用于某一种语言的规则会另有说明。
规则选取
本文是适用于不同应用场景的规则集合,读者可选取适合自己需求的规则。
指出某种错误的规则,如有“不可”、“不应”等字样的规则应尽量被选取,有“禁用”等字样的规则可能只适用于某一场景,可酌情选取。
如果将本文作为培训内容,为了全面理解各种场景下存在的问题,应选取全部规则。
规则列表
- R1.1 敏感数据不应以明文形式写入代码
- R1.2 敏感数据不可被系统外界感知
- R1.3 敏感数据在使用后应被有效清理
- R1.4 公共成员或全局对象不应记录敏感数据
- R1.5 预判由用户输入造成的不良后果
- R1.6 避免在一个事务中通过路径多次访问同一文件
- R1.7 访问共享数据应遵循合理的同步机制
- R1.8 对文件设定合理的权限
- R1.9 对用户设置合理的权限
- R1.10 不应引用危险符号名称
- R1.11 避免调用具有危险性的函数
- R1.12 不应调用已过时的函数
- R1.13 禁用不安全的字符串函数
- R1.14 确保字符串以空字符结尾
- R1.15 避免使用由实现定义的库函数
- R1.16 除数不可存在值为0的可能性
- R1.17 禁用atof、atoi、atol以及atoll等函数
- R1.18 格式化字符串应为常量
- R1.19 与程序实现相关的信息不可被外界感知
- R1.20 不应硬编码IP地址
- R1.21 避免使用errno
- R2.1 资源管理应遵循面向对象的方法
- R2.2 不可失去对已分配资源的控制
- R2.3 不可失去对已分配内存的控制
- R2.4 不可访问未初始化或已释放的资源
- R2.5 资源不可被重复释放
- R2.6 资源的分配与回收方法应配套使用
- R2.7 用new分配的单个对象应该用delete释放,不应该用delete[]释放
- R2.8 用new分配的数组应使用delete[]释放,不应使用delete释放
- R2.9 对象被move之后的值不应再被使用
- R2.10 对象申请的资源须在析构函数中释放
- R2.11 如果构造函数抛出异常需确保相关资源没有泄漏
- R2.12 C++代码中禁用malloc、free等内存分配与回收函数
- R2.13 在一个语句中最多执行一次显式资源分配
- R2.14 在栈上分配的空间以及非动态申请的资源不可被释放
- R2.15 避免使用在栈上分配内存的函数
- R2.16 避免不必要的内存分配
- R2.17 避免动态内存分配
- R2.18 标准FILE对象不应被复制
- 3.1 Include
- 3.2 Macro
- R3.2.1 宏的命名应遵循合理的方式
- R3.2.2 不可定义具有保留意义的宏名称
- R3.2.3 不可取消定义具有保留意义的宏名称
- R3.2.4 可作为子表达式的宏定义应该用括号括起来
- R3.2.5 宏参数在宏定义的表达式中应该用括号括起来
- R3.2.6 由多个语句组成的宏定义应该用do-while(0)括起来
- R3.2.7 宏的实参个数不可小于形参个数
- R3.2.8 宏的实参个数不可大于形参个数
- R3.2.9 宏参数不应有副作用
- R3.2.10 宏参数数量应在规定范围之内
- R3.2.11 宏名称中不应存在拼写错误
- R3.2.12 不应使用宏定义常量
- R3.2.13 不应使用宏定义类型
- R3.2.14 可由函数实现的功能不应使用宏实现
- R3.2.15 在C++代码中不应使用宏offsetof
- R3.2.16 在宏定义中由#修饰的参数后不应出现##
- 3.3 Directive
- 3.4 Comment
- 3.5 Other
- R4.1 不可修改std命名空间
- R4.2 非全局命名空间中不应存在以main命名的函数
- R4.3 全局对象的初始化不可依赖尚未初始化的其他对象
- R4.4 不应在头文件的全局作用域中使用using directive
- R4.5 头文件中不应定义匿名命名空间
- R4.6 全局或命名空间作用域中不应存在即不是const也不是static的对象
- R4.7 全局或命名空间作用域中不应存在非const对象
- R4.8 全局对象不应同时被static和const关键字修饰
- R4.9 匿名命名空间中不应使用静态声明
- R4.10 头文件中不应存在由static关键字修饰的非成员对象、数组或函数
- R4.11 命名空间作用域中禁用using namespace std之外的using directive
- R4.12 不应在命名空间中引用自身
- R4.13 不应定义全局inline命名空间
- R4.14 全局对象、函数、类型以及命名空间名称不应太短
- 5.1 Class
- R5.1.1 类的非常量数据成员均应为private
- R5.1.2 类的非常量数据成员不应定义为protected
- R5.1.3 类不应即有public数据成员又有private数据成员
- R5.1.4 有虚函数的基类应具有虚析构函数
- R5.1.5 对于菱形继承应将基类设为虚基类
- R5.1.6 存在赋值运算符或析构函数时,不应缺少拷贝构造函数
- R5.1.7 存在拷贝构造函数或析构函数时,不应缺少拷贝赋值运算符
- R5.1.8 存在拷贝构造函数或赋值运算符时,不应缺少析构函数
- R5.1.9 存在移动构造函数时,不应缺少移动赋值运算符
- R5.1.10 存在移动赋值运算符,不应缺少移动构造函数
- R5.1.11 可接受一个参数的构造函数需用explicit关键字限定
- R5.1.12 重载的类型转换运算符需用explicit关键字限定
- R5.1.13 不应过度使用explicit关键字
- R5.1.14 带模板的赋值运算符不应覆盖拷贝或移动赋值运算符
- R5.1.15 带模板的构造函数不应覆盖拷贝或移动构造函数
- R5.1.16 重载的new和delete运算符应配对出现
- R5.1.17 抽象类禁用拷贝赋值运算符
- R5.1.18 数据成员的数量应在规定范围之内
- R5.1.19 存在构造、析构或虚函数的类不应采用struct关键字
- 5.2 Enum
- 5.3 Union
- 6.1 Naming
- 6.2 Qualifier
- 6.3 Specifier
- 6.4 Declarator
- 6.5 Object
- 6.6 Parameter
- 6.7 Function
- 6.8 Bitfield
- 6.9 Complexity
- 6.10 Other
- R7.1 确保异常的安全性
- R7.2 异常类的构造函数或异常信息相关的函数不应抛出异常
- R7.3 析构函数不可抛出异常
- R7.4 与STL标准库相关的hash过程不应抛出异常
- R7.5 对象的swap过程不可抛出异常
- R7.6 移动构造函数和移动赋值运算符不可抛出异常
- R7.7 禁用含throw关键字的异常规格说明
- R7.8 重新抛出异常时应使用空throw表达式(throw;)
- R7.9 不应在catch块外使用空throw表达式(throw;)
- R7.10 不应抛出过于宽泛的异常
- R7.11 不应抛出非异常类型的对象
- R7.12 不应将指针作为异常抛出
- R7.13 不应抛出NULL
- R7.14 不应抛出nullptr
- R7.15 禁用C++异常
- R8.1 main函数返回值的类型只应为int
- R8.2 main函数不应被重载,也不应声明为inline、static或constexpr
- R8.3 函数不应在头文件中实现
- R8.4 不应定义过于复杂的内联函数
- R8.5 函数的参数名称在声明和实现处应保持一致
- R8.6 多态类的对象作为参数时不应采用值传递的方式
- R8.7 不应存在未被使用的具名形式参数
- R8.8 由const修饰的参数应为引用或指针
- R8.9 局部变量在使用前必须初始化
- R8.10 成员须在声明处或构造时初始化
- R8.11 基类对象构造完毕之前不可调用成员函数
- R8.12 在面向构造或析构函数体的catch块中不可访问非静态成员
- R8.13 成员初始化应遵循声明的顺序
- R8.14 在构造函数中不应调用虚函数
- R8.15 在析构函数中不应调用虚函数
- R8.16 拷贝构造函数应避免实现复制之外的功能
- R8.17 赋值运算符应妥善处理参数就是自身对象时的情况
- R8.18 不应存在得不到执行机会的代码
- R8.19 有返回值的函数其所有分枝都应有明确的返回值
- R8.20 不可返回局部对象的地址或引用
- R8.21 避免无效的写入
- R8.22 函数返回值不应为const对象
- R8.23 返回值应与函数的返回类型相符
- R8.24 函数返回值不应为相同的常量
- R8.25 基本类型的返回值不应使用const修饰
- R8.26 属性为noreturn的函数中不应出现return语句
- R8.27 属性为noreturn的函数返回类型只应为void
- R8.28 不应出现多余的跳转语句
- R8.29 va_start或va_copy应配合va_end使用
- R8.30 函数模版不应被特化
- R8.31 函数的标签数量应在规定范围之内
- R8.32 函数的行数应在规定范围之内
- R8.33 lambda表达式的行数应在规定范围之内
- R8.34 函数参数的数量应在规定范围之内
- R8.35 禁止goto语句向平级的或更深层的其他作用域跳转
- R8.36 禁止goto语句向前跳转
- R8.37 禁用goto语句
- R8.38 禁用setjmp、longjmp
- R8.39 避免递归实现
- R8.40 不应存在重复的函数实现
- 9.1 If
- R9.1.1 if语句不应被分号隔断
- R9.1.2 在if...else-if分枝中不应有重复的条件
- R9.1.3 在if...else-if分枝中不应有被遮盖的条件
- R9.1.4 if分枝和else分枝的代码不应完全相同
- R9.1.5 if...else-if各分枝的代码不应完全相同
- R9.1.6 if分枝和其隐含的else分枝的代码不应完全相同
- R9.1.7 没有else子句的if语句与其后续代码相同是可疑的
- R9.1.8 if分枝和else分枝的起止语句不应相同
- R9.1.9 if语句作用域的范围不应有误
- R9.1.10 如果if关键字前面是右大括号,if关键字应另起一行
- R9.1.11 if语句的条件不应为赋值表达式
- R9.1.12 if语句不应为空
- R9.1.13 if...else-if分枝数量应在规定范围之内
- R9.1.14 if分枝中的语句应该用大括号括起来
- R9.1.15 所有if...else-if分枝都应以else子句结束
- 9.2 For
- 9.3 While
- 9.4 Do
- 9.5 Switch
- R9.5.1 switch语句不应被分号隔断
- R9.5.2 switch语句不应为空
- R9.5.3 case常量的范围不可超出switch变量的范围
- R9.5.4 switch语句中任何子句都应从属于某个case或default分枝
- R9.5.5 每个case分枝应直接从属于switch结构
- R9.5.6 不应存在紧邻default标签的空case标签
- R9.5.7 不应存在内容完全相同的case分枝
- R9.5.8 switch语句的条件变量或表达式不应为bool型
- R9.5.9 不应使用只有default标签的switch语句
- R9.5.10 不应使用只有一个case标签的switch语句
- R9.5.11 switch语句分枝数量应在规定范围之内
- R9.5.12 switch语句应配有default分枝
- R9.5.13 每个非空的switch分枝都应该用无条件的break语句终止
- R9.5.14 switch语句应该用大括号括起来
- R9.5.15 switch语句不应嵌套
- 9.6 Try
- 9.7 Catch
- 10.1 Logic
- 10.2 Arithmetic
- R10.2.1 不应存在没有效果的表达式
- R10.2.2 逗号表达式的子表达式应具有必要的副作用
- R10.2.3 赋值表达式中不应存在被赋值变量的自增或自减运算
- R10.2.4 子表达式的求值不应依赖特定的顺序
- R10.2.5 注意运算符优先级,不可产生非预期的结果
- R10.2.6 不在同一数组中的指针不可比较或相减
- R10.2.7 bool型变量或表达式不应参与大小比较、位运算、自增自减等运算
- R10.2.8 不应出现复合赋值的错误形式
- R10.2.9 避免出现复合赋值的可疑形式
- R10.2.10 &=、|=、-=、/=、%=左右子表达式不应相同
- R10.2.11 不应使用NULL对非指针变量赋值或初始化
- R10.2.12 赋值运算符与单目运算符之间应有空格,单目运算符与变量或表达式之间不应有空格
- R10.2.13 赋值运算符左右子表达式不应重复
- R10.2.14 除法运算符、求余运算符左右子表达不应重复
- R10.2.15 减法运算符左右子表达式不应重复
- R10.2.16 异或运算符左右子表达式不应重复
- R10.2.17 负号不应作用于无符号整数
- R10.2.18 不应重复使用一元运算符
- R10.2.19 运算结果不应溢出
- R10.2.20 位运算符不应作用于有符号整数
- R10.2.21 移位数量不可超过相关类型比特位的数量
- 10.3 Comparison
- 10.4 Call
- 10.5 Sizeof
- 10.6 Assertion
- 10.7 Complexity
- 10.8 Other
- R11.1 注意可疑的字符常量
- R11.2 字符常量中不可存在应转义而未转义的字符
- R11.3 字符串常量中不可存在应转义而未转义的字符
- R11.4 不应使用非标准转义字符
- R11.5 不同前缀的字符串常量不可连接在一起
- R11.6 字符串常量中不应存在拼写错误
- R11.7 整数或浮点数常量的后缀应使用大写字母
- R11.8 禁用8进制常量
- R11.9 整数或浮点数常量应使用标准后缀
- R11.10 小心遗漏逗号导致的非预期字符串连接
- R11.11 不应存在magic number
- R11.12 不应存在magic string
- R11.13 不应使用多字符常量
- R12.1 避免类型转换造成的数据丢失
- R12.2 避免向下类型转换
- R12.3 指针与整数不应相互转换
- R12.4 类型转换时不应去掉const、volatile等属性
- R12.5 不应强制转换无继承关系的类型
- R12.6 不应强制转换非公有继承关系的类型
- R12.7 多态类型与基本类型不应相互转换
- R12.8 不可直接转换不同的字符串类型
- R12.9 避免类型转换造成的指针运算错误
- R12.10 对函数以及函数指针不应进行类型转换
- R12.11 向下类型转换时应使用dynamic_cast
- R12.12 对new表达式不应进行类型转换
- R12.13 不应存在多余的类型转换
- R12.14 可用static_cast、dynamic_cast完成的类型转换不可使用reinterpret_cast
- R12.15 在C++代码中禁用C风格类型转换
- R12.16 使用reinterpret_cast需有文档说明
- R13.1 对内存的读写应在有效的边界内进行
- R13.2 数组下标不可越界
- R13.3 为缓冲区分配足够的空间
- R13.4 memset等函数不应作用于带有虚函数的对象
- R13.5 memset等函数长度相关的参数不应有误
- R13.6 memset等函数填充值相关的参数不应有误
- R14.1 避免空指针解引用
- R14.2 注意逻辑表达式内的空指针解引用
- R14.3 应判断malloc等内存分配函数的返回值是否为空
- R14.4 用dynamic_cast转换指针时应判断结果是否为空
- R14.5 不可解引用已被释放的指针
- R14.6 不应将非零常量值赋值给指针
- R14.7 不应使用false等布尔常量对指针赋值或初始化
- R14.8 不应使用'\0'或L'\0'等字符常量对指针赋值或初始化
- R14.9 不应使用常数0对指针赋值
- R14.10 指针不应与bool型常量比较大小
- R14.11 指针不应与char型常量比较大小
- R14.12 不应判断指针大于、大于等于、小于、小于等于0
- R14.13 避免无效的空指针检查
- R14.14 不应重复检查指针是否为空
- R14.15 不应判断this指针是否为空
- R14.16 析构函数中不可使用delete this
- R14.17 禁用delete this
- R14.18 sizeof作用于指针是可疑的
- R14.19 指针在释放后应置空
- R15.1 空格应遵循统一风格
- R15.2 大括号应遵循统一风格
- R15.3 NULL和nullptr不应混用
- R15.4 在C++代码中不应使用NULL,应使用nullptr
- R15.5 赋值表达式不应作为子表达式
- R15.6 不应存在多余的分号
C/C++安全规则集合
Bjarne Stroustrup: “C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off.”
针对C、C++语言,本文收录了409种需要重点关注的问题,可为制定编程规范提供依据,也可为代码审计以及相关培训提供指导意见,适用于桌面、服务端以及嵌入式等软件系统。
每个问题对应一条规则,每条规则可直接作为规范条款或审计检查点,本文是适用于不同应用场景的规则集合,读者可根据自身需求从中选取某个子集作为规范或审计依据,从而提高软件产品的安全性。
规则说明
规则按如下主题分为15个类别:
- Security:敏感数据保护、攻击防御等问题
- Resource:资源分配、使用与回收
- Precompile:预处理指令、宏、注释等问题
- Global:全局及命名空间作用域相关问题
- Type:类型相关的设计与实现
- Declaration:声明
- Exception:异常
- Function:函数实现
- Control:流程控制
- Expression:表达式
- Literal:常量
- Cast:类型转换
- Buffer:缓冲区
- Pointer:指针
- Style:样式、风格等问题
每条规则包括:
- 编号:规则在本文中的章节编号,以“R”开头,称为Section-ID
- 名称:用简练的短语描述违反规则的状况,以“ID_”开头,称为Fault-ID
- 标题:规则的定义
- 说明:规则设立的原因、示例、违反规则的后果、改进建议、参照依据、参考资料等内容
当代码出现违反规则的情况时,可分为:
- Error:可直接导致错误的问题
- Warning:可导致错误或存在隐患的问题
- Suspicious:代码的可疑形式
- Suggestion:对提高代码质量的建议
规则的说明包含:
- 示例:规则相关的示例代码,指明符合规则(Compliant)的和违反规则(Non-compliant)的情况
- 相关:与当前规则有相关性的规则,可作为扩展阅读的线索
- 依据:规则依照的ISO/IEC标准,C规则以ISO/IEC 9899:2011为主,C++规则以ISO/IEC 14882:2011为主
- 配置:某些规则的对象可由用户指定,审计工具可以此为参照实现定制化功能
- 参考:规则参考的其他规范条款,如C++ Core Guidelines、MISRA、CWE、SEI CERT等,也可作为扩展阅读的线索
规则的相关性分为:
- 特化:设规则A的特殊情况需要由规则B阐明,称规则B是规则A的特化
- 泛化:与特化相反,称规则A是规则B的泛化
- 相交:设两个规则针对不同的问题,但在内容上有一定的交集,称这两个规则相交
规则以“标准名称:版本 章节编号(段落编号)-性质
”的格式引用标准,如“ISO/IEC 14882:2011 5.6(4)-undefined
”,表示引用C++11标准的第5章第6节第4段说明的具有undefined性质的问题。
其中“性质”分为:
- undefined:一般指某种错误,使程序产生undefined behavior
- unspecified:标准不作明确规定的情况,由编译器或环境自主定义,具有随意性
- implementation defined:由实现定义,也是由编译器或环境自主定义,与unspecified不同,要求有明确的文档支持
- deprecated:已过时或已废弃的用法
本文以ISO/IEC 9899:2011以及ISO/IEC 14882:2011为主要依据,兼顾C18、C++17以及历史标准,没有特殊说明的规则同时适用于C语言和C++语言,只适用于某一种语言的规则会另有说明。
规则选取
本文是适用于不同应用场景的规则集合,读者可选取适合自己需求的规则。
指出某种错误的规则,如有“不可”、“不应”等字样的规则应尽量被选取,有“禁用”等字样的规则可能只适用于某一场景,可酌情选取。
如果将本文作为培训内容,为了全面理解各种场景下存在的问题,应选取全部规则。
规则列表
- R1.1 敏感数据不应以明文形式写入代码
- R1.2 敏感数据不可被系统外界感知
- R1.3 敏感数据在使用后应被有效清理
- R1.4 公共成员或全局对象不应记录敏感数据
- R1.5 预判由用户输入造成的不良后果
- R1.6 避免在一个事务中通过路径多次访问同一文件
- R1.7 访问共享数据应遵循合理的同步机制
- R1.8 对文件设定合理的权限
- R1.9 对用户设置合理的权限
- R1.10 不应引用危险符号名称
- R1.11 避免调用具有危险性的函数
- R1.12 不应调用已过时的函数
- R1.13 禁用不安全的字符串函数
- R1.14 确保字符串以空字符结尾
- R1.15 避免使用由实现定义的库函数
- R1.16 除数不可存在值为0的可能性
- R1.17 禁用atof、atoi、atol以及atoll等函数
- R1.18 格式化字符串应为常量
- R1.19 与程序实现相关的信息不可被外界感知
- R1.20 不应硬编码IP地址
- R1.21 避免使用errno
- R2.1 资源管理应遵循面向对象的方法
- R2.2 不可失去对已分配资源的控制
- R2.3 不可失去对已分配内存的控制
- R2.4 不可访问未初始化或已释放的资源
- R2.5 资源不可被重复释放
- R2.6 资源的分配与回收方法应配套使用
- R2.7 用new分配的单个对象应该用delete释放,不应该用delete[]释放
- R2.8 用new分配的数组应使用delete[]释放,不应使用delete释放
- R2.9 对象被move之后的值不应再被使用
- R2.10 对象申请的资源须在析构函数中释放
- R2.11 如果构造函数抛出异常需确保相关资源没有泄漏
- R2.12 C++代码中禁用malloc、free等内存分配与回收函数
- R2.13 在一个语句中最多执行一次显式资源分配
- R2.14 在栈上分配的空间以及非动态申请的资源不可被释放
- R2.15 避免使用在栈上分配内存的函数
- R2.16 避免不必要的内存分配
- R2.17 避免动态内存分配
- R2.18 标准FILE对象不应被复制
- 3.1 Include
- 3.2 Macro
- R3.2.1 宏的命名应遵循合理的方式
- R3.2.2 不可定义具有保留意义的宏名称
- R3.2.3 不可取消定义具有保留意义的宏名称
- R3.2.4 可作为子表达式的宏定义应该用括号括起来
- R3.2.5 宏参数在宏定义的表达式中应该用括号括起来
- R3.2.6 由多个语句组成的宏定义应该用do-while(0)括起来
- R3.2.7 宏的实参个数不可小于形参个数
- R3.2.8 宏的实参个数不可大于形参个数
- R3.2.9 宏参数不应有副作用
- R3.2.10 宏参数数量应在规定范围之内
- R3.2.11 宏名称中不应存在拼写错误
- R3.2.12 不应使用宏定义常量
- R3.2.13 不应使用宏定义类型
- R3.2.14 可由函数实现的功能不应使用宏实现
- R3.2.15 在C++代码中不应使用宏offsetof
- R3.2.16 在宏定义中由#修饰的参数后不应出现##
- 3.3 Directive
- 3.4 Comment
- 3.5 Other
- R4.1 不可修改std命名空间
- R4.2 非全局命名空间中不应存在以main命名的函数
- R4.3 全局对象的初始化不可依赖尚未初始化的其他对象
- R4.4 不应在头文件的全局作用域中使用using directive
- R4.5 头文件中不应定义匿名命名空间
- R4.6 全局或命名空间作用域中不应存在即不是const也不是static的对象
- R4.7 全局或命名空间作用域中不应存在非const对象
- R4.8 全局对象不应同时被static和const关键字修饰
- R4.9 匿名命名空间中不应使用静态声明
- R4.10 头文件中不应存在由static关键字修饰的非成员对象、数组或函数
- R4.11 命名空间作用域中禁用using namespace std之外的using directive
- R4.12 不应在命名空间中引用自身
- R4.13 不应定义全局inline命名空间
- R4.14 全局对象、函数、类型以及命名空间名称不应太短
- 5.1 Class
- R5.1.1 类的非常量数据成员均应为private
- R5.1.2 类的非常量数据成员不应定义为protected
- R5.1.3 类不应即有public数据成员又有private数据成员
- R5.1.4 有虚函数的基类应具有虚析构函数
- R5.1.5 对于菱形继承应将基类设为虚基类
- R5.1.6 存在赋值运算符或析构函数时,不应缺少拷贝构造函数
- R5.1.7 存在拷贝构造函数或析构函数时,不应缺少拷贝赋值运算符
- R5.1.8 存在拷贝构造函数或赋值运算符时,不应缺少析构函数
- R5.1.9 存在移动构造函数时,不应缺少移动赋值运算符
- R5.1.10 存在移动赋值运算符,不应缺少移动构造函数
- R5.1.11 可接受一个参数的构造函数需用explicit关键字限定
- R5.1.12 重载的类型转换运算符需用explicit关键字限定
- R5.1.13 不应过度使用explicit关键字
- R5.1.14 带模板的赋值运算符不应覆盖拷贝或移动赋值运算符
- R5.1.15 带模板的构造函数不应覆盖拷贝或移动构造函数
- R5.1.16 重载的new和delete运算符应配对出现
- R5.1.17 抽象类禁用拷贝赋值运算符
- R5.1.18 数据成员的数量应在规定范围之内
- R5.1.19 存在构造、析构或虚函数的类不应采用struct关键字
- 5.2 Enum
- 5.3 Union
- 6.1 Naming
- 6.2 Qualifier
- 6.3 Specifier
- 6.4 Declarator
- 6.5 Object
- 6.6 Parameter
- 6.7 Function
- 6.8 Bitfield
- 6.9 Complexity
- 6.10 Other
- R7.1 确保异常的安全性
- R7.2 异常类的构造函数或异常信息相关的函数不应抛出异常
- R7.3 析构函数不可抛出异常
- R7.4 与STL标准库相关的hash过程不应抛出异常
- R7.5 对象的swap过程不可抛出异常
- R7.6 移动构造函数和移动赋值运算符不可抛出异常
- R7.7 禁用含throw关键字的异常规格说明
- R7.8 重新抛出异常时应使用空throw表达式(throw;)
- R7.9 不应在catch块外使用空throw表达式(throw;)
- R7.10 不应抛出过于宽泛的异常
- R7.11 不应抛出非异常类型的对象
- R7.12 不应将指针作为异常抛出
- R7.13 不应抛出NULL
- R7.14 不应抛出nullptr
- R7.15 禁用C++异常
- R8.1 main函数返回值的类型只应为int
- R8.2 main函数不应被重载,也不应声明为inline、static或constexpr
- R8.3 函数不应在头文件中实现
- R8.4 不应定义过于复杂的内联函数
- R8.5 函数的参数名称在声明和实现处应保持一致
- R8.6 多态类的对象作为参数时不应采用值传递的方式
- R8.7 不应存在未被使用的具名形式参数
- R8.8 由const修饰的参数应为引用或指针
- R8.9 局部变量在使用前必须初始化
- R8.10 成员须在声明处或构造时初始化
- R8.11 基类对象构造完毕之前不可调用成员函数
- R8.12 在面向构造或析构函数体的catch块中不可访问非静态成员
- R8.13 成员初始化应遵循声明的顺序
- R8.14 在构造函数中不应调用虚函数
- R8.15 在析构函数中不应调用虚函数
- R8.16 拷贝构造函数应避免实现复制之外的功能
- R8.17 赋值运算符应妥善处理参数就是自身对象时的情况
- R8.18 不应存在得不到执行机会的代码
- R8.19 有返回值的函数其所有分枝都应有明确的返回值
- R8.20 不可返回局部对象的地址或引用
- R8.21 避免无效的写入
- R8.22 函数返回值不应为const对象
- R8.23 返回值应与函数的返回类型相符
- R8.24 函数返回值不应为相同的常量
- R8.25 基本类型的返回值不应使用const修饰
- R8.26 属性为noreturn的函数中不应出现return语句
- R8.27 属性为noreturn的函数返回类型只应为void
- R8.28 不应出现多余的跳转语句
- R8.29 va_start或va_copy应配合va_end使用
- R8.30 函数模版不应被特化
- R8.31 函数的标签数量应在规定范围之内
- R8.32 函数的行数应在规定范围之内
- R8.33 lambda表达式的行数应在规定范围之内
- R8.34 函数参数的数量应在规定范围之内
- R8.35 禁止goto语句向平级的或更深层的其他作用域跳转
- R8.36 禁止goto语句向前跳转
- R8.37 禁用goto语句
- R8.38 禁用setjmp、longjmp
- R8.39 避免递归实现
- R8.40 不应存在重复的函数实现
- 9.1 If
- R9.1.1 if语句不应被分号隔断
- R9.1.2 在if...else-if分枝中不应有重复的条件
- R9.1.3 在if...else-if分枝中不应有被遮盖的条件
- R9.1.4 if分枝和else分枝的代码不应完全相同
- R9.1.5 if...else-if各分枝的代码不应完全相同
- R9.1.6 if分枝和其隐含的else分枝的代码不应完全相同
- R9.1.7 没有else子句的if语句与其后续代码相同是可疑的
- R9.1.8 if分枝和else分枝的起止语句不应相同
- R9.1.9 if语句作用域的范围不应有误
- R9.1.10 如果if关键字前面是右大括号,if关键字应另起一行
- R9.1.11 if语句的条件不应为赋值表达式
- R9.1.12 if语句不应为空
- R9.1.13 if...else-if分枝数量应在规定范围之内
- R9.1.14 if分枝中的语句应该用大括号括起来
- R9.1.15 所有if...else-if分枝都应以else子句结束
- 9.2 For
- 9.3 While
- 9.4 Do
- 9.5 Switch
- R9.5.1 switch语句不应被分号隔断
- R9.5.2 switch语句不应为空
- R9.5.3 case常量的范围不可超出switch变量的范围
- R9.5.4 switch语句中任何子句都应从属于某个case或default分枝
- R9.5.5 每个case分枝应直接从属于switch结构
- R9.5.6 不应存在紧邻default标签的空case标签
- R9.5.7 不应存在内容完全相同的case分枝
- R9.5.8 switch语句的条件变量或表达式不应为bool型
- R9.5.9 不应使用只有default标签的switch语句
- R9.5.10 不应使用只有一个case标签的switch语句
- R9.5.11 switch语句分枝数量应在规定范围之内
- R9.5.12 switch语句应配有default分枝
- R9.5.13 每个非空的switch分枝都应该用无条件的break语句终止
- R9.5.14 switch语句应该用大括号括起来
- R9.5.15 switch语句不应嵌套
- 9.6 Try
- 9.7 Catch
- 10.1 Logic
- 10.2 Arithmetic
- R10.2.1 不应存在没有效果的表达式
- R10.2.2 逗号表达式的子表达式应具有必要的副作用
- R10.2.3 赋值表达式中不应存在被赋值变量的自增或自减运算
- R10.2.4 子表达式的求值不应依赖特定的顺序
- R10.2.5 注意运算符优先级,不可产生非预期的结果
- R10.2.6 不在同一数组中的指针不可比较或相减
- R10.2.7 bool型变量或表达式不应参与大小比较、位运算、自增自减等运算
- R10.2.8 不应出现复合赋值的错误形式
- R10.2.9 避免出现复合赋值的可疑形式
- R10.2.10 &=、|=、-=、/=、%=左右子表达式不应相同
- R10.2.11 不应使用NULL对非指针变量赋值或初始化
- R10.2.12 赋值运算符与单目运算符之间应有空格,单目运算符与变量或表达式之间不应有空格
- R10.2.13 赋值运算符左右子表达式不应重复
- R10.2.14 除法运算符、求余运算符左右子表达不应重复
- R10.2.15 减法运算符左右子表达式不应重复
- R10.2.16 异或运算符左右子表达式不应重复
- R10.2.17 负号不应作用于无符号整数
- R10.2.18 不应重复使用一元运算符
- R10.2.19 运算结果不应溢出
- R10.2.20 位运算符不应作用于有符号整数
- R10.2.21 移位数量不可超过相关类型比特位的数量
- 10.3 Comparison
- 10.4 Call
- 10.5 Sizeof
- 10.6 Assertion
- 10.7 Complexity
- 10.8 Other
- R11.1 注意可疑的字符常量
- R11.2 字符常量中不可存在应转义而未转义的字符
- R11.3 字符串常量中不可存在应转义而未转义的字符
- R11.4 不应使用非标准转义字符
- R11.5 不同前缀的字符串常量不可连接在一起
- R11.6 字符串常量中不应存在拼写错误
- R11.7 整数或浮点数常量的后缀应使用大写字母
- R11.8 禁用8进制常量
- R11.9 整数或浮点数常量应使用标准后缀
- R11.10 小心遗漏逗号导致的非预期字符串连接
- R11.11 不应存在magic number
- R11.12 不应存在magic string
- R11.13 不应使用多字符常量
- R12.1 避免类型转换造成的数据丢失
- R12.2 避免向下类型转换
- R12.3 指针与整数不应相互转换
- R12.4 类型转换时不应去掉const、volatile等属性
- R12.5 不应强制转换无继承关系的类型
- R12.6 不应强制转换非公有继承关系的类型
- R12.7 多态类型与基本类型不应相互转换
- R12.8 不可直接转换不同的字符串类型
- R12.9 避免类型转换造成的指针运算错误
- R12.10 对函数以及函数指针不应进行类型转换
- R12.11 向下类型转换时应使用dynamic_cast
- R12.12 对new表达式不应进行类型转换
- R12.13 不应存在多余的类型转换
- R12.14 可用static_cast、dynamic_cast完成的类型转换不可使用reinterpret_cast
- R12.15 在C++代码中禁用C风格类型转换
- R12.16 使用reinterpret_cast需有文档说明
- R13.1 对内存的读写应在有效的边界内进行
- R13.2 数组下标不可越界
- R13.3 为缓冲区分配足够的空间
- R13.4 memset等函数不应作用于带有虚函数的对象
- R13.5 memset等函数长度相关的参数不应有误
- R13.6 memset等函数填充值相关的参数不应有误
- R14.1 避免空指针解引用
- R14.2 注意逻辑表达式内的空指针解引用
- R14.3 应判断malloc等内存分配函数的返回值是否为空
- R14.4 用dynamic_cast转换指针时应判断结果是否为空
- R14.5 不可解引用已被释放的指针
- R14.6 不应将非零常量值赋值给指针
- R14.7 不应使用false等布尔常量对指针赋值或初始化
- R14.8 不应使用'\0'或L'\0'等字符常量对指针赋值或初始化
- R14.9 不应使用常数0对指针赋值
- R14.10 指针不应与bool型常量比较大小
- R14.11 指针不应与char型常量比较大小
- R14.12 不应判断指针大于、大于等于、小于、小于等于0
- R14.13 避免无效的空指针检查
- R14.14 不应重复检查指针是否为空
- R14.15 不应判断this指针是否为空
- R14.16 析构函数中不可使用delete this
- R14.17 禁用delete this
- R14.18 sizeof作用于指针是可疑的
- R14.19 指针在释放后应置空