Valgrind,“未初始化的价值”错误

时间:2012-06-28 14:01:06

标签: c linux memory-management initialization valgrind

在我的C程序中,我使用malloc()分配内存,与calloc()相反,初始化内存,它可能仍然包含垃圾。大多数情况下,在分配的上下文中,我不对malloc()分配的内存进行任何更改。 (例如,在初始化包含缓冲区的结构的函数中,我不会对缓冲区的内存进行更改,但稍后会更改。)

Valgrind给了我很多的错误:

  • 条件跳转或移动取决于未初始化的值
  • 使用大小为4的未初始化值

确定永远不会读取在这些情况下未初始化的内存。

我应该忽略它们还是最好在分配时初始化内存?如果我应该忽略它们,如何在Valgrind中停用此错误消息?


示例1

==4253== Conditional jump or move depends on uninitialised value(s)
==4253==    at 0x408EB8E: vfprintf (vfprintf.c:1624)
==4253==    by 0x4093C2E: printf (printf.c:35)
==4253==    by 0x40624D2: (below main) (libc-start.c:226)
==4253==  Uninitialised value was created by a heap allocation
==4253==    at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4253==    by 0x8048938: gk_StreamBufferNode_init (stream.c:101)
==4253==    by 0x8048D0D: gk_Stream_bufferWriteProc (stream.c:252)
==4253==    by 0x8048665: main (main.c:21)

代码

int gk_StreamBufferNode_init(gk_StreamBufferNode* node, int buffer_size,
                             gk_AllocProc malloc) {
    node->buffer = malloc(buffer_size);     // line 101
    if (node->buffer == NULL) {
        return GKIT_FAILEDALLOC;
    }
    node->next = NULL;
    return GKIT_NOERR;
}

示例2

==4253== Conditional jump or move depends on uninitialised value(s)
==4253==    at 0x402DA39: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4253==    by 0x8048C6E: gk_Stream_bufferWriteProc (stream.c:230)
==4253==    by 0x8048665: main (main.c:21)
==4253==  Uninitialised value was created by a heap allocation
==4253==    at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4253==    by 0x8048CE0: gk_Stream_bufferWriteProc (stream.c:248)
==4253==    by 0x8048665: main (main.c:21)

代码

    /* ... */
    int available_bytes = binfo->buffer_size - bnode->filled;
    int bytes_to_go = size * count;
    int offset = 0;
    int node_offset = 0;
    gk_StreamBufferNode* new_node;
    void* destination = NULL;
    void* source = NULL;

    while (bytes_to_go > 0) {
        destination = bnode->buffer + bnode->filled + node_offset;
        source = buffer + offset;
        if (available_bytes > bytes_to_go) {
            memcpy(destination, source, bytes_to_go);    // line 230
            bnode->filled += bytes_to_go;
            offset += bytes_to_go;
            node_offset = bytes_to_go;
            bytes_to_go = 0;
        }
        else {
            memcpy(destination, source, available_bytes);
            offset += available_bytes;
            node_offset = 0;
            bytes_to_go -= available_bytes;
            bnode->filled += available_bytes;

            #ifdef DEBUG
                assert(bnode->filled == bnode->buffer_size);
            #endif // DEBUG

            // Allocate a new buffer node.
            new_node = (gk_StreamBufferNode*) malloc(sizeof(gk_StreamBufferNode));    // line 248
            if (new_node == NULL) {
                return GKIT_FAILEDALLOC;
            }
            int success = gk_StreamBufferNode_init(new_node, binfo->buffer_size,
                                                   malloc);
            if (success <= GKIT_ERROR) {
                free(new_node);
                return GKIT_FAILEDALLOC;
            }
            bnode->next = new_node;
            bnode = new_node;
            available_bytes = binfo->buffer_size;
        }
    }

2 个答案:

答案 0 :(得分:6)

在这两种情况下,您只需分配内存而不进行初始化。最简单的方法是使用calloc代替malloc将其清零。对于简单情况,此可能是一个很好的策略,例如,如果您稍后使用buffer作为要打印的字符串。对于更复杂的用例,将值分配给各个字段,如果C99从复合文字中分配整个结构,则更好:

toto * t = malloc(sizeof(*t));    
*t = (toto){ 0 };

答案 1 :(得分:3)

您的代码不应期望未初始化的内存包含任何值,因此依赖于这些值的条件跳转会显示严重问题。

你应该初始化内存(到一些已知的值,例如0),或者除非它们已被初始化,否则不要引用它的内容。