CERT C++ 规范
CERT Cpp 规范
https://ww2.mathworks.cn/help/bugfinder/cert-c-rules.html?lang=en
声明与初始化
[DCL30-C] 为对象声明恰当的存储期。
[DCL39-C] 避免结构体填充带来的信息泄露。
[DCL40-C] 不要为同一个函数或对象创建不兼容的声明。
[DCL50-CPP] 不要定义 C 风格的可变参数函数。
[DCL51-CPP] 不要声明或定义保留标识符。
[DCL52-CPP] 切勿用 const 或 volatile 限定引用类型。
[DCL53-CPP] 不要编写存在语法歧义的声明。
[DCL54-CPP] 在同一作用域内成对重载内存分配与释放函数。
[DCL55-CPP] 跨信任边界传递类对象时,避免信息泄露。
[DCL56-CPP] 避免静态对象初始化过程中的循环依赖。
[DCL57-CPP] 不要让异常从析构函数或内存释放函数中逃逸。
[DCL58-CPP] 不要修改标准命名空间。
[DCL59-CPP] 不要在头文件中定义未命名命名空间。
[DCL60-CPP] 遵守单一定义规则。
表达式
[EXP34-C] 不要解引用空指针。
[EXP35-C] 不要修改具有临时生存期的对象。
[EXP36-C] 不要将指针强制转换为对齐要求更严格的指针类型。
[EXP37-C] 调用函数时传入正确数量和类型的参数。
[EXP39-C] 不要通过类型不兼容的指针访问变量。
[EXP42-C] 不要对填充数据进行比较操作。
[EXP45-C] 不要在选择语句中执行赋值操作。
[EXP46-C] 不要对类布尔操作数使用位运算符。
[EXP47-C] 调用 va_arg 时不要传入类型不正确的参数。
[EXP50-CPP] 不要依赖带副作用操作数的求值顺序。
[EXP51-CPP] 不要通过类型不正确的指针删除数组。
[EXP52-CPP] 不要依赖未求值操作数中的副作用。
[EXP53-CPP] 不要读取未初始化的内存。
[EXP54-CPP] 不要在对象的生存期之外访问对象。
[EXP55-CPP] 不要通过非 cv 限定类型访问 cv 限定的对象。
[EXP56-CPP] 不要调用语言链接不匹配的函数。
[EXP57-CPP] 不要对指向不完整类的指针进行强制转换或删除操作。
[EXP58-CPP] 为 va_start 传入正确类型的对象。
[EXP59-CPP] 对合法的类型和成员使用 offsetof() 宏。
[EXP60-CPP] 不要跨执行边界传递非标准布局类型的对象。
[EXP61-CPP] lambda 对象的生存期不得超过其任何引用捕获的对象。
[EXP62-CPP] 不要访问对象表示中不属于其值表示的二进制位。
[EXP63-CPP] 不要依赖被移动后对象的值。
整数
[INT30-C] 确保无符号整数运算不会发生回绕。
[INT31-C] 确保整数转换不会导致数据丢失或被错误解读。
[INT32-C] 确保有符号整数运算不会发生溢出。
[INT33-C] 确保除法和取余运算不会出现除零错误。
[INT34-C] 不要对表达式执行负数位数的移位,或移位位数大于等于操作数本身的位宽。
[INT35-C] 使用正确的整数精度。
[INT36-C] 谨慎执行指针与整数之间的相互转换。
[INT50-CPP] 不要强制转换为取值范围外的枚举值。
容器
[ARR30-C] 不要生成或使用越界的指针或数组下标。
[ARR37-C] 不要对指向非数组对象的指针进行整数加减操作。
[ARR38-C] 确保库函数不会生成无效指针。
[ARR39-C] 不要对指针执行缩放后的整数加减操作。
[CTR50-CPP] 确保容器的下标和迭代器处于合法范围内。
[CTR51-CPP] 使用合法的引用、指针和迭代器来访问容器元素。
[CTR52-CPP] 确保库函数不会发生溢出。
[CTR53-CPP] 使用合法的迭代器区间。
[CTR54-CPP] 不要对不属于同一容器的迭代器执行减法操作。
[CTR55-CPP] 对迭代器使用加法运算符时,确保结果不会溢出。
[CTR56-CPP] 不要对多态对象使用指针算术运算。
[CTR57-CPP] 提供合法的排序谓词。
[CTR58-CPP] 谓词函数对象不应是可修改的。
字符与字符串
[STR30-C] 不要尝试修改字符串字面量。
[STR31-C] 确保字符串的存储空间足以容纳字符数据和空终止符。
[STR32-C] 不要向期望字符串的库函数传入非空终止的字符序列。
[STR34-C] 字符转换为更大的整数类型前,先强制转换为 unsigned char 类型。
[STR37-C] 字符处理函数的参数必须能表示为 unsigned char 类型。
[STR38-C] 不要混淆窄字符、宽字符字符串及其对应的处理函数。
[STR50-CPP] 确保字符串的存储空间足以容纳字符数据和空终止符。
[STR51-CPP] 不要尝试通过空指针构造 std::string 对象。
[STR52-CPP] 使用合法的引用、指针和迭代器来访问 basic_string 的元素。
[STR53-CPP] 对元素访问执行范围检查。
内存管理
[MEM30-C] 不要访问已释放的内存。
[MEM31-C] 动态分配的内存不再使用时应及时释放。
[MEM34-C] 仅释放动态分配的内存。
[MEM35-C] 为对象分配足够的内存。
[MEM36-C] 不要通过调用 realloc() 修改对象的对齐方式。
[MEM50-CPP] 不要访问已释放的内存。
[MEM51-CPP] 正确释放动态分配的资源。
[MEM52-CPP] 检测并处理内存分配错误。
[MEM53-CPP] 手动管理对象生存期时,显式执行对象的构造与析构。
[MEM54-CPP] 为 placement new 提供对齐正确、存储空间充足的指针。
[MEM55-CPP] 遵守动态存储管理函数替换的相关要求。
[MEM56-CPP] 不要将已被持有所有权的指针值存入无关的智能指针中。
[MEM57-CPP] 避免对过对齐类型使用默认的 operator new。
输入与输出
[FIO30-C] 禁止用户输入进入格式字符串。
[FIO32-C] 不要对设备执行仅适用于文件的操作。
[FIO34-C] 区分从文件读取的字符与 EOF、WEOF。
[FIO37-C] 不要假定 fgets() 或 fgetws() 调用成功时一定会返回非空字符串。
[FIO38-C] 不要复制 FILE 对象。
[FIO39-C] 对流交替执行输入输出操作时,中间必须执行刷新或定位操作。
[FIO40-C] fgets() 或 fgetws() 调用失败时重置字符串。
[FIO41-C] 调用 getc()、putc()、getwc()、putwc() 时,流参数不要带有副作用。
[FIO42-C] 文件不再使用时应及时关闭。
[FIO44-C] fsetpos() 仅使用 fgetpos() 返回的合法值。
[FIO45-C] 访问文件时避免 TOCTOU(检查时间与使用时间)竞态条件。
[FIO46-C] 不要访问已关闭的文件。
[FIO47-C] 使用合法的格式字符串。
[FIO50-CPP] 对文件流交替执行输入输出操作时,中间必须执行定位操作。
[FIO51-CPP] 文件不再使用时应及时关闭。
异常与错误处理
[ERR30-C] 调用会设置 errno 的库函数前,先将 errno 置为 0;且仅当函数返回值表明调用失败后,再检查 errno 的值。
[ERR32-C] 不要依赖 errno 的不确定值。
[ERR33-C] 检测并处理标准库的错误。
[ERR34-C] 字符串转换为数值时检测并处理错误。
[ERR50-CPP] 不要让程序异常终止。
[ERR51-CPP] 处理所有异常。
[ERR52-CPP] 不要使用 setjmp() 或 longjmp() 函数。
[ERR53-CPP] 不要在构造函数或析构函数的函数级 try 块处理程序中,引用基类或类的数据成员。
[ERR54-CPP] 异常捕获处理程序应按参数类型从派生程度最高到最低的顺序排列。
[ERR55-CPP] 遵守异常规范。
[ERR56-CPP] 确保异常安全。
[ERR57-CPP] 异常处理过程中不要发生资源泄漏。
[ERR58-CPP] 处理 main() 函数开始执行前抛出的所有异常。
[ERR59-CPP] 不要跨执行边界抛出异常。
[ERR60-CPP] 异常对象必须具备不抛出异常的拷贝构造能力。
[ERR61-CPP] 通过左值引用捕获异常。
[ERR62-CPP] 字符串转换为数值时检测并处理错误。
面向对象编程
[OOP50-CPP] 不要在构造函数或析构函数中调用虚函数。
[OOP51-CPP] 不要对派生类对象进行切片操作。
[OOP52-CPP] 删除多态对象时,其基类必须具备虚析构函数。
[OOP53-CPP] 按规范顺序编写构造函数的成员初始化列表。
[OOP54-CPP] 妥善处理自拷贝赋值操作。
[OOP55-CPP] 不要使用指向成员的指针运算符访问不存在的成员。
[OOP56-CPP] 遵守替换处理程序的相关要求。
[OOP57-CPP] 优先使用特殊成员函数和重载运算符,而非 C 标准库函数。
[OOP58-CPP] 拷贝操作不得修改源对象。
并发
[CON33-C] 使用库函数时避免竞态条件。
[CON37-C] 多线程程序中不要调用 signal() 函数。
[CON40-C] 不要在一个表达式中两次引用同一个原子变量。
[CON41-C] 将可能虚假失败的函数封装在循环中。
[CON43-C] 多线程代码中禁止出现数据竞争。
[CON50-CPP] 不要销毁处于锁定状态的互斥量。
[CON51-CPP] 确保异常发生时主动持有的锁能被正确释放。
[CON52-CPP] 多线程访问位域时防止数据竞争。
[CON53-CPP] 按预定义顺序加锁以避免死锁。
[CON54-CPP] 将可能虚假唤醒的函数封装在循环中。
[CON55-CPP] 使用条件变量时,保证线程安全与活性。
[CON56-CPP] 不要对调用线程已持有的非递归互斥量执行投机性加锁。
其他规则
[ENV30-C] 不要修改特定函数返回值所引用的对象。
[ENV31-C] 执行可能使环境指针失效的操作后,不要依赖该环境指针。
[ENV32-C] 所有退出处理程序必须正常返回。
[ENV33-C] 不要调用 system() 函数。
[ENV34-C] 不要存储特定函数返回的指针。
[FLP30-C] 不要使用浮点变量作为循环计数器。
[FLP32-C] 预防并检测数学函数中的定义域和值域错误。
[FLP34-C] 确保浮点转换的结果在目标类型的取值范围内。
[FLP36-C] 整数值转换为浮点类型时保留精度。
[FLP37-C] 不要通过对象表示来比较浮点值。
[MSC30-C] 不要使用 rand() 函数生成伪随机数。
[MSC32-C] 为伪随机数生成器设置正确的种子。
[MSC33-C] 不要向 asctime() 函数传入非法数据。
[MSC37-C] 确保控制流永远不会到达非 void 函数的末尾。
[MSC38-C] 若预定义标识符可能仅以宏的形式实现,不要将其当作对象处理。
[MSC39-C] 不要对值不确定的 va_list 调用 va_arg()。
[MSC40-C] 不要违反语言约束。
[MSC41-C] 切勿硬编码敏感信息。
[MSC50-CPP] 不要使用 std::rand() 生成伪随机数。
[MSC51-CPP] 确保随机数生成器被正确设置种子。
[MSC52-CPP] 有返回值的函数必须在所有退出路径都返回值。
[MSC53-CPP] 不要从声明为 [[noreturn]] 的函数中返回。
[MSC54-CPP] 信号处理函数必须是普通函数。
[PRE30-C] 不要通过拼接生成通用字符名。
[PRE31-C] 避免不安全宏的参数带有副作用。
[PRE32-C] 不要在调用类函数宏时使用预处理指令。
[SIG31-C] 不要在信号处理函数中访问共享对象。
[SIG34-C] 不要在可中断的信号处理函数内部调用 signal()。
[SIG35-C] 不要从计算异常的信号处理函数中返回。