web-dev-qa-db-ja.com

valgrind-アドレス----は、サイズ8のブロックが割り当てられた後の0バイトです

まず、類似の質問があったことを知っています。しかし、私は実際に原始的なCデータ型に関するより一般的な簡単な質問が欲しいです。ここにあります。

main.cこれらの文字列を設定する関数を呼び出します。

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

内部get_options

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

私のプログラムは正常に動作しますが、Valgrindは私が間違っていることを教えてくれます。

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

エラーについて説明してくださいAddress 0xa2edd18 is 0 bytes after a block of size 8 alloc'd?この問題を解決するにはどうすればよいですか?

22
Oz123

strcpyは、ヌルターミネータ文字'\0'を追加します。スペースを割り当てるのを忘れました:

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

5文字のスペースを追加する必要があります:".tde"サフィックス用に4つ、'\0'ターミネーター用にもう1つ。現在のコードは4のみを割り当てるため、最後の書き込みは、新しいファイル名に割り当てたブロックの直後のスペース(つまり、後の0バイト)に行われます。

注:コードには共通の問題があります。reallocの結果を、再割り当てされるポインターに直接割り当てます。 reallocが成功した場合はこれで問題ありませんが、失敗するとメモリリークが発生します。このエラーを修正するには、別の変数にreallocの結果を保存し、*filenameに値を戻す前にNULLを確認する必要があります。

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

*filenameに直接割り当てると、メモリリークが発生します。これは、*filenameが下を指しているポインターが失敗すると上書きされ、回復不能になるためです。

37
dasblinkenlight