Valgrind memcheck使用了一堆启发式方法来避免对“无害”使用未初始化的值的误报,因为这种使用在正确和不正确的功能代码中都是常见的。
尤其是在您以一种严肃的,也许是“不可逆的”方式实际使用这样的值之前,例如基于该值的跳跃,它不会令人沮丧。
这意味着有时错误会发生在距问题根源很远的地方,甚至无法确定涉及哪个值。是否有某种方法可以在运行时“检查”值,例如use(x)
,如果x
未初始化,将使Valgrind在该位置发出错误?
答案 0 :(得分:1)
您可以使use(x)
宏使用Valgrind VALGRIND_CHECK_VALUE_IS_DEFINED
Client Request来当场出错。
为此,请添加valgrind/memcheck.h
并将您的宏定义为
#define use(x) VALGRIND_CHECK_VALUE_IS_DEFINED(x)
并确保始终传递左值。
您还可以使用--track-origins=yes
运行memcheck进行更严格的跟踪,该跟踪应显示未初始化数据的起源。
另请参阅the Valgrind FAQ on uninitialised value errors,其中解释了这两种方法,以及为何Valgrind不会抱怨复制未初始化的值。
答案 1 :(得分:0)
通常,类似这样的事情需要对代码进行检测(通过工具自动完成,或手动插入源代码中)。
如我的评论中所述,如果您可以自己插入use(x)
语句,则可以执行以下操作:
static FILE* dev_null = 0;
static void use_var(char* var_addr, size_t var_size)
{
if (dev_null == 0) /* make sure we only open FILE* dev_null once */
{
dev_null = fopen("/dev/null", "wb");
assert(dev_null != 0); /* opening /dev/null CAN actually fail */
}
size_t i;
for (i = 0; i < var_size; ++i)
{
fputc(var_addr[i], dev_null); /* read every byte in the variable, write to dev_null */
}
}
#define use(x) use_var((char*)&x, sizeof(x))
/* Example of usage */
int main()
{
long x = 80;
struct { double d; char c[123]; } y;
memset(&y, 0, sizeof(y) - 1); /* initialize all bytes in y, except the last */
double z[2] = {3.14, 42.0};
use(x);
use(y);
use(z);
return 0;
}
但是,使用struct
包含对齐填充的问题。
填充永远不会被用于任何东西,因此这可能是传递未初始化数据的合法原因。在这种情况下,Valgrind可能会导致有关未初始化读取的虚假错误。
这两篇文章专门讨论了这个问题: Is there anyway a valgrind message "Conditional jump or move depends on uninitialized value" can be a so called 'false positive'
Should I worry about "Conditional jump or move depends on uninitialised value(s)"?