检查时
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char c[20];
size_t l;
l = fread(c, sizeof c, 1, stdin);
if (l != 1)
return 1;
return c[0] == 42;
}
跟铿锵,我明白了
$ clang --analyze -Xclang -analyzer-checker=alpha x.c
x.c:13:14: warning: The left operand of '==' is a garbage value
return c[0] == 42;
~~~~ ^
$ clang -v
clang version 7.0.1 (Fedora 7.0.1-4.fc29)
那时c
真的有可能包含垃圾吗?如果没有,我怎么能避免警告(没有明显的c
初始化)?
因为它似乎是普遍的共识,这是一个误报,我想集中在如何避免警告的方式。
确实,fread()
是一个标准函数,分析器应该知道它们的语义,例如对于memset()
已经。但是我对可以使用的更通用的方法感兴趣,例如关于图书馆职能。
我会以某种方式调用一些特殊功能(让我们称之为assert_defined()
)
l = fread(c, sizeof c, 1, stdin);
assert_defined(c, l * sizeof c);
是的
l * sizeof c
上的c
字节被初始化了clang是否知道注释
inline static void assert_defined(void const *p, size_t cnt)
__attribute__((__dear_compiler_this_memory_is_not_garbage__(1,2)))
{
}
或者有相关的技巧
int i = i;
这可以防止gcc发出“未初始化的警告”?
是的它可能包含垃圾 - 如果fread()
失败。
如果c[0]
失败,分析器应该理解检查保证fread
不被读取将需要分析器理解fread()
函数的语义。对于任何非平凡的代码而言,这是一项计算成本高昂的任务,并且需要查看库源或标准库语义的编码 - 这是可能的,但只会发现涉及“已知函数”的一小部分问题。
初始化阵列将避免此特定问题:
char c[20] = {0} ;
我会说编译器不应该知道函数fread()的工作原理。从编译器的角度来看,fread()可能会也可能不会修改'c'。
因此,如果您没有在特定情况下显式初始化变量,则编译器没有选择,只能发出警告。