bugprone-not-null-terminated-result¶
查找可能导致非空终止结果的函数调用。通常,字符串的正确长度为 strlen(src) + 1
或该表达式的等长,因为空终止符需要额外的空间。没有空终止符会导致在读取字符串时出现未定义行为。
以下及其相应的 wchar_t
基函数将被检查
memcpy
, memcpy_s
, memchr
, memmove
, memmove_s
, strerror_s
, strncmp
, strxfrm
以下是一个现实世界的例子,程序员忘记增加传递的第三个参数,即 size_t length
。这就是分配的内存长度不足以容纳空终止符的原因。
static char *stringCpy(const std::string &str) {
char *result = reinterpret_cast<char *>(malloc(str.size()));
memcpy(result, str.data(), str.size());
return result;
}
除了发出警告之外,修复还将重写所有必要的代码。它还尝试调整目标数组的容量
static char *stringCpy(const std::string &str) {
char *result = reinterpret_cast<char *>(malloc(str.size() + 1));
strcpy(result, str.data());
return result;
}
注意:它不能保证重写所有路径敏感的内存分配。
‘memcpy()’ 的转换规则¶
可以将 memcpy()
和 memcpy_s()
调用重写为以下四个函数: strcpy()
, strncpy()
, strcpy_s()
, strncpy_s()
,其中后两个是前两个的更安全版本。它分别重写了基于 wchar_t
的内存处理函数。
基于目标数组的重写¶
如果复制到目标数组不会溢出 [1],则新函数应该是旧的复制函数(以
cpy
结尾),因为它比安全版本更高效。如果复制到目标数组可能溢出 [1],并且
WantToUseSafeFunctions
设置为 true,并且可以获取目标数组的容量,则新函数可以是安全版本(以cpy_s
结尾)。如果新函数可能是安全版本,并且分析的是 C++ 文件,并且目标数组是普通的
char
/wchar_t
,没有un/signed
,则可以省略目标数组的长度。如果新函数可能是安全版本,并且目标数组是
un/signed
,则需要将其强制转换为普通的char *
/wchar_t *
。
- [1] 可能溢出
如果目标数组的容量未知。
如果给定长度等于目标数组的容量。
基于源字符串长度的重写¶
如果给定长度为
strlen(source)
或该表达式的等长,则新函数应该是旧的复制函数(以cpy
结尾),因为它比安全版本(以cpy_s
结尾)更高效。否则,我们假设程序员希望复制 'N' 个字符,因此新函数是类似
ncpy
的,它复制 'N' 个字符。
使用 ‘strlen()’ 或该表达式的等长的转换¶
它分别转换了基于 wchar_t
的内存和字符串处理函数(其中只有 strerror_s
没有基于 wchar_t
的别名)。
内存处理函数¶
memcpy
请访问 ‘memcpy()’ 的转换规则 部分。
memchr
通常有一个 C 样式的强制转换,需要将其删除,因为新函数 strchr
的返回类型是正确的。给定的长度将被删除。
memmove
如果有安全函数可用,新函数是 memmove_s
,它有一个新的第二个参数,它是目标数组的长度,它被调整,并且源字符串的长度增加 1。如果安全函数不可用,则给定长度增加 1。
memmove_s
给定的长度增加 1。
字符串处理函数¶
strerror_s
给定的长度增加 1。
strncmp
如果第三个参数是第一个或第二个参数的 length + 1
,则必须将其截断,不进行 + 1
操作。
strxfrm
给定的长度增加 1。
选项¶
- WantToUseSafeFunctions¶
值 true 指定目标环境被认为实现了以 ‘_s’ 为后缀的内存和字符串处理函数,这些函数比旧版本(例如 ‘memcpy_s()’)更安全。默认值为 true。