也许只是我度过了奇怪的一天,但我有一些关于Clang警告的问题,需要一个简短的例子。
假设有一段时间有这样一段代码
/// \file unsafe.c
#include <stddef.h>
static int goo (int * pi, size_t a)
{
return pi[a];
}
int main (int argc, char *argv[])
{
(void)argc;
(void)argv;
int goz[4] = { 0, };
return goo(goz, 0);
}
Run Code Online (Sandbox Code Playgroud)
然后你按照如下方式使用 Clang
# clang --version
clang version 16.0.3
Target: i686-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files (x86)\LLVM\bin
# clang -std=c11 -Weverything unsafe.c -o unsafe.exe
unsafe.c:4:24: warning: 'pi' is an unsafe pointer used for buffer access
[-Wunsafe-buffer-usage]
static int goo (int …Run Code Online (Sandbox Code Playgroud) 我确信编码中存在很多缓冲区溢出风险,其中许多风险是通过标准库的“_s”安全函数解决的。尽管如此,我发现自己有时对其中一些感到困惑。
假设我有一些这样的片段
uint8_t a[5];
...
size_t z = 6;
...
memset(a, 0, z); // Overflow!
Run Code Online (Sandbox Code Playgroud)
一些编译器(C11)可能建议更好地使用memset_s; 因为我是一个糟糕的程序员,所以我刚刚将我的代码更新为这个全新的东西,我的方式:
uint8_t a[5];
...
rsize_t max_array = 56; // Slipped finger, head in the clouds, etc.
rsize_t z = 6;
...
memset_s(a, max_array, 0, z); // So what?
Run Code Online (Sandbox Code Playgroud)
如果我只是将错误添加到另一个参数,那会memset_s更好吗?memset
增加的安全性在哪里,如果添加一个新参数只是添加一个可能会出错的新参数。我本可以在第一个修订版中更正我的代码,并且仍然可以合法地调用缓冲区上定义良好的操作。
抛开带有未经检查的零指针的情况,怎么会memset比更糟糕呢memset_s?
[编辑]
经过一番努力,我还发现了导致我的设置中出现警告的设置。这可能对某人有帮助。
该警告来自 Clang-tidy,在 Visual Studio 扩展“Clang power tools”中调用。在其默认设置中,它启用了 Clang-tidy检查器“ security.insecureAPI.DeprecatedOrUnsafeBufferHandling ”,它模仿默认的 …
C11 中的声明strtok_s及其用法看起来与 Visual Studio 2022 (17.4.4) 和 GCC 12.2.0 捆绑的最新编译器(查看 MinGW64 发行版)中的in 编译器非常不同。strtok_s
我担心这种不同的形式早在 C11 之前就已被开发为更安全且被接受的替代品strtok。如果有人想要使用strtok_s并保持 C11 合规,现在会发生什么?
编译器提供的库是否兼容 C11?
也许只是我被一些显而易见的事情愚弄了,有人可以帮助我......
这是 C11(与 C17 和 C23 的早期草案类似):
char *strtok_s(char * restrict s1,
rsize_t * restrict s1max,
const char * restrict s2,
char ** restrict ptr);
Run Code Online (Sandbox Code Playgroud)
同样可以在safec 库中找到一个很好的参考
而MSC/VC和 GCC 的形式为
char* strtok_s(
char* str,
const char* delimiters,
char** context
);
Run Code Online (Sandbox Code Playgroud) 在 ARM GCC(纯 C 代码)上,当我声明一个常量时,如下所示
__attribute__((used,section(".rodata.$AppID")))
const uint8_t ApplicationID[16] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x12, 0x34, 0x00, 0x00
};
Run Code Online (Sandbox Code Playgroud)
我没有在代码中引用它,它已被优化,并在地图文件上的废弃输入部分中列出。仅当我在源代码的其他地方引用它时,它才会包含在二进制输出中。
仅仅“ used”标签就足够了吗?在GCC手册(6.34.1公共变量属性)中我读到:
用过的
此属性附加到具有静态存储的变量,意味着即使看起来该变量未被引用,也必须发出该变量。
意思是把它放在指定段的固定内存地址,供单独的应用程序检查它
我正在运行 NXP MCUXpresso 11.1 提供的 ARM GCC,报告详细版本为
GNU C17 (GNU Tools for Arm Embedded Processors 8-2019-q3-update) version 8.3.1 20190703 (release) [gcc-8-branch revision 273027] (arm-none-eabi)
compiled by GNU C version 5.3.1 20160211, GMP version 6.1.0, MPFR version 3.1.4, …Run Code Online (Sandbox Code Playgroud)