c - Valgrind 给出“条件跳转或移动取决于未初始化的值”错误
问题描述
我正在努力理解和解决“条件跳转或移动取决于未初始化的值”错误 valgrind 点,到目前为止没有成功。
我尝试初始化代码中的几乎所有内容(结构的数据元素除外),即使很明显没有必要。我尝试调试并检查每个 stack_t-object 的所有成员是否已初始化并具有值。一切都无济于事 - valgrind 不断得出结论,由于未初始化的值而存在内存错误。
有趣的是,所有测试都完美无瑕,除了 valgrind 问题。我一直在缩小代码的范围,直到找到 valgrind 不喜欢的特定代码段。
它在下面。这是来自文件 stack.c:
#define GET_STACK_SIZE(x, y) (offsetof(stack_t, _data) + x * y)
typedef struct stack
{
size_t _capacity;
size_t _element_size;
size_t _top_of_stack;
char _data[1];
} stack_t;
stack_t *StackCreate(size_t capacity, size_t element_size)
{
stack_t *new_st = NULL;
assert(element_size > 0);
assert(capacity > 0);
new_st = malloc(GET_STACK_SIZE(capacity, element_size));
if (NULL == new_st)
{
return NULL;
}
new_st->_capacity = capacity;
new_st->_element_size = element_size;
new_st->_top_of_stack = 0;
return new_st;
}
stack_t *StackCopy(const stack_t *other)
{
stack_t *new_st;
assert(NULL != other);
new_st = StackCreate(other->_capacity, other->_element_size);
if (NULL == new_st)
return NULL;
memcpy(new_st, other, GET_STACK_SIZE(other->_capacity, other->_element_size));
new_st->_capacity = other->_capacity;
new_st->_element_size = other->_element_size;
new_st->_top_of_stack = other->_top_of_stack;
return new_st;
}
int StackEquals(const stack_t *st1, const stack_t *st2)
{
return memcmp(st1, st2,
GET_STACK_SIZE(st1->_capacity, st1->_element_size)) == 0;
}
这是来自我的测试文件:
#define NUM_OF_STACKS_IN_TEST (2)
#define CAPACITY_MULT (5)
stack_t *stacks[NUM_OF_STACKS_IN_TEST] = {NULL};
int init()
{
int i = 0;
for (; i < NUM_OF_STACKS_IN_TEST; ++i)
{
switch (i)
{
case 0:
stacks[i] = StackCreate((i + 1) * CAPACITY_MULT, sizeof(char));
if (NULL == stacks[i])
return EXIT_FAILURE;
break;
case 1:
stacks[i] = StackCopy(stacks[0]);
if (NULL == stacks[i])
return EXIT_FAILURE;
default:
break;
}
}
return EXIT_SUCCESS;
}
int StackCreateTest(void)
{
size_t i;
for (i = 0; i<NUM_OF_STACKS_IN_TEST>> 1; ++i)
{
if (StackEquals(stacks[i], stacks[i + 1]) != 1)
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int main(void)
{
if (EXIT_SUCCESS != init())
{
puts("initialization failed");
}
RUN_TEST(StackCreateTest); /* just a macro that runs StackCreateTest function */
end(); /* frees memory allocation */
return EXIT_SUCCESS;
}
据可以说,一切看起来都很好。但是 valgrind 给出了这个错误:
==25611== Conditional jump or move depends on uninitialised value(s)
==25611== at 0x4C35E6F: bcmp (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25611== by 0x108C4F: StackEquals (stack.c:92)
==25611== by 0x108D19: StackCreateTest (stack_test.c:113)
==25611== by 0x108C83: main (stack_test.c:72)
==25611== Uninitialised value was created by a heap allocation
==25611== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25611== by 0x108A62: StackCreate (stack.c:46)
==25611== by 0x108D79: init (stack_test.c:175)
==25611== by 0x108C67: main (stack_test.c:67)
==25611==
==25611== Conditional jump or move depends on uninitialised value(s)
==25611== at 0x4C35E91: bcmp (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25611== by 0x108C4F: StackEquals (stack.c:92)
==25611== by 0x108D19: StackCreateTest (stack_test.c:113)
==25611== by 0x108C83: main (stack_test.c:72)
==25611== Uninitialised value was created by a heap allocation
==25611== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25611== by 0x108A62: StackCreate (stack.c:46)
==25611== by 0x108D79: init (stack_test.c:175)
==25611== by 0x108C67: main (stack_test.c:67)
==25611==
==25611== Conditional jump or move depends on uninitialised value(s)
==25611== at 0x108D1D: StackCreateTest (stack_test.c:113)
==25611== by 0x108C83: main (stack_test.c:72)
==25611== Uninitialised value was created by a heap allocation
==25611== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25611== by 0x108A62: StackCreate (stack.c:46)
==25611== by 0x108D79: init (stack_test.c:175)
==25611== by 0x108C67: main (stack_test.c:67)
==25611==
StackCreateTest is OK!
==25611==
==25611== HEAP SUMMARY:
==25611== in use at exit: 0 bytes in 0 blocks
==25611== total heap usage: 3 allocs, 3 frees, 1,082 bytes allocated
==25611==
==25611== All heap blocks were freed -- no leaks are possible
==25611==
==25611== For counts of detected and suppressed errors, rerun with: -v
==25611== ERROR SUMMARY: 6 errors from 3 contexts (suppressed: 0 from 0)
我将不胜感激任何可能对该主题有所启发的帮助或想法。
更新: 正如 kevin 和 KamilCuk 正确指出的那样,问题是结构 stack_t 的 _data 成员未初始化,因此 memcpy 和 memcmp 实际上正在使用未初始化的内存,因为 valgrind 正确检测到
解决方案
尽管通过句柄读取未初始化的内存char*
不是未定义的行为(也不是通过memcpy
和memcmp
函数),但始终在读取之前初始化内存仍然被认为是一种好习惯。
Valgrind 正确诊断“问题”,您new_st = malloc(GET_STACK_SIZE(capacity, element_size));
分配内存并且不初始化范围内的内存( offsetof(stack_t, _data), offsetof(stack_t, _data) + x * y ]
。然后代码从中读取memcpy(new_st, other, GET_STACK_SIZE(other->_capacity, other->_element_size));
并比较它memcmp(st1, st2,
- 因此 valgrind 显示未初始化的字节错误。
解决方法很简单——初始化内存。使用calloc
或调用memset
like memset(new_st.data, 0, x * y)
。
推荐阅读
- psql - psql:警告:额外的命令行参数被忽略
- ios - Swift:调用中的参数缺少参数
- python - 有没有办法可以运行由 python 中的函数打印的代码?
- php - PHP 7.4+ 类属性类型
- html - 如何在单击时隐藏按钮中的蓝色阴影?
- ios - Swift 可解码请求对象
- nginx - Nginx 使用 SSL 提供 404
- bash - 如何从内部浏览器页面(例如“brave://rewards”)抓取数据
- python - 有没有比 stripe.Customer.retrieve 函数更快的替代方法?
- javascript - 如何使父容器的高度设置为固定 px 高度和子内容高度之间的最大值?