Pertanyaan Valgrind, "kesalahan nilai diinisialisasi (s)"


Dalam program C saya, saya mengalokasikan memori menggunakan malloc() yang mana, berbeda dengan calloc(), tidak menginisialisasi memori dan mungkin masih mengandung sampah. Sebagian besar, dalam konteks alokasi, saya tidak membuat perubahan pada memori yang dialokasikan oleh malloc(). (Misalnya dalam fungsi untuk menginisialisasi struct yang berisi buffer, saya tidak membuat perubahan pada memori buffer, tetapi nanti).

Valgrind memberi saya banyak kesalahan ini:

  • Lompatan atau perpindahan kondisional bergantung pada nilai yang tidak diinisialisasi (s)
  • Penggunaan nilai ukuran terinisialisasi 4

saya saya yakin untuk tidak pernah membaca dari memori yang tidak diinisialisasi dalam kasus ini.

Haruskah saya mengabaikannya atau lebih baik untuk menginisialisasi memori pada alokasi? Dalam hal saya harus mengabaikan mereka, bagaimana saya dapat menonaktifkan pesan kesalahan ini di Valgrind?


Contoh 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)

Kode:

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;
}

Contoh 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)

Kode:

    /* ... */
    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;
        }
    }

5
2018-06-28 14:01


asal


Jawaban:


Dalam kedua kasus, Anda hanya mengalokasikan memori tanpa menginisialisasi. Cara termudah adalah menggunakan calloc dari pada malloc untuk membidiknya. Ini mungkin jadilah strategi yang baik untuk kasus sederhana, misalnya jika nanti Anda menggunakan buffer sebagai string yang akan dicetak. Untuk kasus penggunaan yang lebih rumit, berikan nilai ke masing-masing bidang, atau bahkan lebih baik jika Anda memiliki C99 yang menugaskan seluruh struktur dari literal majemuk:

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

6
2018-06-28 14:22



Kode Anda seharusnya tidak mengharapkan memori terinisialisasi mengandung nilai apa pun, sehingga memiliki lompatan kondisional bergantung pada ini menunjukkan masalah serius.

Anda harus menginisialisasi memori (ke beberapa nilai yang diketahui, misalnya. 0), atau tidak mengacu pada kontennya kecuali mereka telah diinisialisasi.


3
2018-06-28 14:07