首页 > 解决方案 > 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 正确检测到

标签: cvalgrind

解决方案


尽管通过句柄读取未初始化的内存char*不是未定义的行为(也不是通过memcpymemcmp函数),但始终在读取之前初始化内存仍然被认为是一种好习惯

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或调用memsetlike memset(new_st.data, 0, x * y)


推荐阅读