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;
}
}