我想知道下面的示例是否是Clang SA误报,如果是,是否有办法抑制它?
这里的关键是我通过将其转换为单词而不是逐字段复制(或memcpy)来复制包含位字段的结构。逐字段复制和memcpy都不会触发警告,但是以单词复制(强制转换后)会引发“未初始化的访问”警告。这是在只能进行单词访问的嵌入式系统上,并且这些类型的单词副本很常见。
下面是示例代码:
#include <stdio.h>
#include <string.h>
struct my_fields_t {
unsigned int f0: 16;
unsigned int f1: 8;
unsigned int f2: 8;
};
int main(void) {
struct my_fields_t var1, var2;
// initialize all the fields in var1.
var1.f0 = 1;
var1.f1 = 2;
var1.f2 = 3;
// Method #1: copy var1 -> var2 as a word (sizeof(unsigned int) = 4).
unsigned int *src = (unsigned int *) &var1;
unsigned int *dest = (unsigned int *) &var2;
*dest = *src;
// Method #2: copy var1->var2 field-by-field [NO SA WARNINGS]
// var2.f0 = var1.f0;
// var2.f1 = var1.f1;
// var2.f2 = var1.f2;
// Method #3: use memcpy to copy var1 to var2 [NO SA WARNINGS]
// memcpy(&var2, &var1, sizeof(struct my_fields_t));
printf("%d, %d, %d\n", var1.f0, var1.f1, var1.f2);
printf("%d, %d, %d\n", var2.f0, var2.f1, var2.f2); // <--- Function call argument is an uninitialized value
printf("sizeof(unsigned int) = %ld\n", sizeof(unsigned int));
}
以下是输出:
$ clang --version
clang version 4.0.0 (tags/RELEASE_401/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
$ clang -Wall clang_sa.c
$ ./a.out
1, 2, 3
1, 2, 3
sizeof(unsigned int) = 4
$ scan-build clang clang_sa.c
scan-build: Using '<snipped>/clang-4.0' for static analysis
clang_sa.c:33:3: warning: Function call argument is an uninitialized value
printf("%d, %d, %d\n", var2.f0, var2.f1, var2.f2); // <--- Function call argument is an uninitialized value
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
scan-build: 1 bug found.
在上面的示例中,很明显,var2中的所有字段都将由单词copy初始化。因此,clang SA不应抱怨非初始化访问。
感谢您的帮助/见解。
答案 0 :(得分:0)
在禁止显示特定警告方面,来自documentation:
问:如何抑制特定的分析仪警告?
尽管目前正在研究抑制分析器警告的机制,但目前尚无可靠的机制。 ...
但是在下一个问题上,它向您展示了您可以通过用#ifdef
块包围代码来标记要在静态分析期间跳过的代码块:
问:如何有选择地排除分析器检查的代码?
当静态分析器使用clang解析源文件时,它隐式定义了预处理器宏__clang_analyzer__
。可以使用此宏有选择地排除分析器检查的代码。 ...
因此,您可以这样做:
#ifdef __clang_analyzer__
#define COPY_STRUCT(DEST, SRC) (DEST) = (SRC)
#else
#define COPY_STRUCT(DEST, SRC) do { \
const unsigned int *src = (const void *)&(SRC); \
unsigned int *dest = (void *)&(DEST); \
*dest = *src; \
} while(0)
#endif
COPY_STRUCT(var2, var1);