bugprone-unsafe-functions¶
检查具有更安全、更可靠的替换函数,或因设计缺陷而被视为已弃用的函数。该检查严重依赖于 C11 的 **附录 K.** “边界检查接口” 中的函数。
- 该检查实现了 CERT C 编码标准中的以下规则:
cert-msc24-c 和 cert-msc33-c 作为此检查的别名重定向到这里。
不安全的函数¶
如果启用了 ReportDefaultFunctions
,则会报告以下函数。
如果 *附录 K.* 可用,则建议使用 *附录 K.* 中的替换函数替换以下函数
asctime
, asctime_r
, bsearch
, ctime
, fopen
, fprintf
, freopen
, fscanf
, fwprintf
, fwscanf
, getenv
, gets
, gmtime
, localtime
, mbsrtowcs
, mbstowcs
, memcpy
, memmove
, memset
, printf
, qsort
, scanf
, snprintf
, sprintf
, sscanf
, strcat
, strcpy
, strerror
, strlen
, strncat
, strncpy
, strtok
, swprintf
, swscanf
, vfprintf
, vfscanf
, vfwprintf
, vfwscanf
, vprintf
, vscanf
, vsnprintf
, vsprintf
, vsscanf
, vswprintf
, vswscanf
, vwprintf
, vwscanf
, wcrtomb
, wcscat
, wcscpy
, wcslen
, wcsncat
, wcsncpy
, wcsrtombs
, wcstok
, wcstombs
, wctomb
, wmemcpy
, wmemmove
, wprintf
, wscanf
.
如果 *附录 K.* 不可用,则仅建议使用以下函数替换上述列表中的函数
asctime
,asctime_r
, 建议替换函数:strftime
gets
, 建议替换函数:fgets
以下函数始终会被检查,无论 *附录 K* 是否可用
rewind
, 建议替换函数:fseek
setbuf
, 建议替换函数:setvbuf
如果启用了 ReportMoreUnsafeFunctions
,则还会检查以下函数
bcmp
, 建议替换函数:memcmp
bcopy
, 建议替换函数: 如果 *附录 K* 可用,则为memcpy_s
,否则为memcpy
bzero
, 建议替换函数: 如果 *附录 K* 可用,则为memset_s
,否则为memset
getpw
, 建议替换函数:getpwuid
vfork
, 建议替换函数:posix_spawn
虽然在相关的 CERT 规则中提到,但以下函数会被此检查 **忽略**
atof
, atoi
, atol
, atoll
, tmpfile
.
*附录 K* 的可用性是根据以下宏确定的
__STDC_LIB_EXT1__
: 功能宏,指示库实现中是否存在 *附录 K. “边界检查接口”*
__STDC_WANT_LIB_EXT1__
: 用户定义宏,指示用户请求定义 *附录 K.* 中的函数。
这两个宏都必须定义才能建议使用 *附录 K.* 中的替换函数。 __STDC_LIB_EXT1__
由库实现定义,并且 __STDC_WANT_LIB_EXT1__
必须由用户定义为 1
,**在**包含任何系统头文件之前。
自定义函数¶
选项 CustomFunctions
允许用户定义要检查的自定义函数。格式如下,不包含换行符
bugprone-unsafe-functions.CustomFunctions="
functionRegex1[, replacement1[, reason1]];
functionRegex2[, replacement2[, reason2]];
...
"
这些函数使用 POSIX 扩展正则表达式进行匹配。(注意:正则表达式不支持负向 (?!)
匹配。)
*reason* 是可选的,用于提供有关替换原因的额外信息。默认原因是 *被标记为不安全*。
如果 *replacement* 为空,则将显示 *它不应该被使用* 而不是替换建议。
例如,配置 *^original$, replacement, is deprecated;* 将产生以下诊断消息。
original(); // warning: function 'original' is deprecated; 'replacement' should be used instead.
::std::original(); // no-warning
original_function(); // no-warning
如果正则表达式包含字符 *:*,则它将与限定名称(即 std::original
)匹配,否则正则表达式将与非限定名称(original
)匹配。如果正则表达式以 *::* (或 *^::*)开头,则它将与完全限定名称(::std::original
)匹配。
选项¶
- ReportMoreUnsafeFunctions¶
如果为 *true*,则会将来自广泛使用的 API(如 POSIX)的更多函数添加到要报告的函数列表中。有关此选项启用了哪些函数的完整列表,请参阅检查的主要文档。默认值为 *true*。
示例¶
#ifndef __STDC_LIB_EXT1__
#error "Annex K is not supported by the current standard library implementation."
#endif
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h> // Defines functions from Annex K.
#include <stdio.h>
enum { BUFSIZE = 32 };
void Unsafe(const char *Msg) {
static const char Prefix[] = "Error: ";
static const char Suffix[] = "\n";
char Buf[BUFSIZE] = {0};
strcpy(Buf, Prefix); // warning: function 'strcpy' is not bounds-checking; 'strcpy_s' should be used instead.
strcat(Buf, Msg); // warning: function 'strcat' is not bounds-checking; 'strcat_s' should be used instead.
strcat(Buf, Suffix); // warning: function 'strcat' is not bounds-checking; 'strcat_s' should be used instead.
if (fputs(buf, stderr) < 0) {
// error handling
return;
}
}
void UsingSafeFunctions(const char *Msg) {
static const char Prefix[] = "Error: ";
static const char Suffix[] = "\n";
char Buf[BUFSIZE] = {0};
if (strcpy_s(Buf, BUFSIZE, Prefix) != 0) {
// error handling
return;
}
if (strcat_s(Buf, BUFSIZE, Msg) != 0) {
// error handling
return;
}
if (strcat_s(Buf, BUFSIZE, Suffix) != 0) {
// error handling
return;
}
if (fputs(Buf, stderr) < 0) {
// error handling
return;
}
}