5

在我的 C 程序中,我使用malloc()which 分配内存,与 相比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;
        }
    }
4

2 回答 2

6

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

toto * t = malloc(sizeof(*t));    
*t = (toto){ 0 };
于 2012-06-28T14:22:38.697 回答
3

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

您应该初始化内存(到某个已知值,例如0),或者不引用它的内容,除非它们已经被初始化。

于 2012-06-28T14:07:59.043 回答