Pertanyaan valgrind - Alamat-adalah 0 byte setelah blok ukuran 8 dialokasikan


Pertama, saya tahu serupa pertanyaan telah diajukan. Namun, saya ingin memiliki pertanyaan sederhana yang lebih umum dengan tipe data C yang benar-benar primitif. Jadi begini.

Di main.c Saya memanggil fungsi untuk mengisi string tersebut:

int
main (int argc, char *argv[]){

    char *host = NULL ;
    char *database ;
    char *collection_name;
    char *filename = ""; 
    char *fields = NULL;
    char *query = NULL;
    ...

    get_options(argc, argv, &host, &database, &collection_name, &filename, 
                &fields, &query, &aggregation);

Dalam get_options:

if (*filename == NULL ) {
   *filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+4);
    strcpy(*filename, *collection_name);
    strcat(*filename, ".tde");  # line 69 
}

Program saya berfungsi dengan baik, tetapi Valgrind memberi tahu saya bahwa saya salah:

==8608== Memcheck, a memory error detector
==8608== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==8608== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==8608== Command: ./coll2tde -h localhost -d test -c test
==8608== 
==8608== Invalid write of size 1
==8608==    at 0x403BE2: get_options (coll2tde.c:69)
==8608==    by 0x402213: main (coll2tde.c:92)
==8608==  Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd
==8608==    at 0x4C28BED: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8608==    by 0x4C28D6F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8608==    by 0x403BBC: get_options (coll2tde.c:67)
==8608==    by 0x402213: main (coll2tde.c:92)

Bisakah Anda menjelaskan kesalahan Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd? Bagaimana saya bisa mengatasi masalah ini?


18
2017-12-24 11:36


asal


Jawaban:


strcpy menambahkan karakter terminator null '\0'. Anda lupa mengalokasikan ruang untuk itu:

*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);

Anda perlu menambahkan ruang untuk 5 karakter: 4 untuk ".tde" suffix, dan satu lagi untuk '\0' terminator. Kode Anda saat ini hanya mengalokasikan 4, sehingga penulisan terakhir dilakukan ke ruang segera setelah blok yang telah Anda alokasikan untuk nama file baru (yaitu 0 byte setelahnya).

catatan: Kode Anda memiliki masalah umum - ia menetapkan hasil realloc langsung ke pointer yang dialokasikan kembali. Ini baik-baik saja kapan realloc berhasil, tetapi menciptakan kebocoran memori ketika gagal. Memperbaiki kesalahan ini membutuhkan menyimpan hasil realloc dalam variabel terpisah, dan memeriksanya NULL sebelum mengembalikan nilainya *filename:

char *tmp = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);
if (tmp != NULL) {
    *filename = tmp;
} else {
    // Do something about the failed allocation
}

Menetapkan langsung ke *filename menciptakan kebocoran memori, karena pointer tersebut *filename telah menunjuk ke bawah akan menjadi ditimpa pada kegagalan, menjadi tidak dapat dipulihkan.


29
2017-12-24 11:39