5

私の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;
        }
    }
4

2 に答える 2

6

どちらの場合も、メモリを初期化せずに割り当てるだけです。最も簡単な方法は、ゼロにするcalloc代わりに使用することです。mallocこれは単純なケースでは良い戦略かもしれませbufferん。例えば、出力される文字列として後で a を使用する場合などです。より複雑な使用例では、個々のフィールドに値を割り当てます。C99 に複合リテラルから構造全体を割り当てさせると、さらに効果的です。

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

コードは、初期化されていないメモリに値が含まれていることを期待すべきではないため、これらに依存する条件付きジャンプがあると、深刻な問題が発生します。

メモリを初期化する必要があります (既知の値、たとえば0)、または初期化されていない限り、その内容を参照しないでください。

于 2012-06-28T14:07:59.043 に答える