[解決済み] Valgrindが "Invalid write of size 8 "で文句を言う。
質問
趣味でやっている小さなプロジェクト( www.github.com/AzP/GLSL-Validate そこで私は古いコード(私自身の好みからすると、cが多すぎ、c++が少なすぎるのですが、まあ、仕方ありません)を取り、LinuxとWindowsで稼働させようとしているのです。何度かクラッシュしたんだけど(今は直ってるといいな)、問題を見つけるためにValgrindを動かし始めてから、自分が受けた苦情を直したいと思うようになったんだ。
このコードのどこが悪いのか(素敵な "magic numbers" があちこちに散らばっていてかなり読みにくいことを除いて)、Valgrind の苦情に関して、私にはわからないのです。
以下のコマンドでValgrindを実行しています。
valgrind --track-origins=yes ./Program
291 //
292 // Malloc a string of sufficient size and read a string into it.
293 //
294 # define MAX_SOURCE_STRINGS 5
295 char** ReadFileData(char *fileName)
296 {
297 FILE *in = fopen(fileName, "r");
298 char *fdata;
299 int count = 0;
300 char**return_data=(char**)malloc(MAX_SOURCE_STRINGS+1);
301
302 //return_data[MAX_SOURCE_STRINGS]=NULL;
303 if (!in) {
304 printf("Error: unable to open input file: %s\n", fileName);
305 return 0;
306 }
307
308 // Count size of file by looping through it
309 while (fgetc(in) != EOF)
310 count++;
311
312 fseek(in, 0, SEEK_SET);
313
314
315 if (!(fdata = (char *)malloc(count+2))) {
316 printf("Error allocating memory\n");
317 return 0;
318 }
319 if (fread(fdata, sizeof(char), count, in) != count) {
320 printf("Error reading input file: %s\n", fileName);
321 return 0;
322 }
323 fdata[count] = '\0';
324 fclose(in);
325 if(count==0){
326 return_data[0]=(char*)malloc(count+2);
327 return_data[0][0]='\0';
328 OutputMultipleStrings=0;
329 return return_data;
330 }
331
332 int len = (int)(ceil)((float)count/(float)OutputMultipleStrings);
333 int ptr_len=0,i=0;
334 while(count>0){
335 return_data[i]=(char*)malloc(len+2);
336 memcpy(return_data[i],fdata+ptr_len,len);
337 return_data[i][len]='\0';
338 count-=(len);
339 ptr_len+=(len);
340 if(count<len){
341 if(count==0){
342 OutputMultipleStrings=(i+1);
343 break;
344 }
345 len = count;
346 }
347 ++i;
348 }
349 return return_data;
350 }
そして、Valgrindの出力です。この
is 0 bytes inside a block of size 6 alloc'd
は無視していいということでしょうか?0バイト』って危険な感じがしないでもないですが?でも、ここに質問を投稿した以上、注意した方がいいと思うのはわかると思うのですが。
==10570== Invalid write of size 8
==10570== at 0x401602: ReadFileData(char*) (StandAlone.cpp:335)
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570== by 0x401016: main (StandAlone.cpp:152)
==10570== Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd
==10570== at 0x4C2880D: malloc (vg_replace_malloc.c:236)
==10570== by 0x401475: ReadFileData(char*) (StandAlone.cpp:300)
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570== by 0x401016: main (StandAlone.cpp:152)
==10570==
==10570== Invalid read of size 8
==10570== at 0x401624: ReadFileData(char*) (StandAlone.cpp:336)
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570== by 0x401016: main (StandAlone.cpp:152)
==10570== Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd
==10570== at 0x4C2880D: malloc (vg_replace_malloc.c:236)
==10570== by 0x401475: ReadFileData(char*) (StandAlone.cpp:300)
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570== by 0x401016: main (StandAlone.cpp:152)
==10570==
==10570== Invalid read of size 8
==10570== at 0x40163F: ReadFileData(char*) (StandAlone.cpp:337)
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570== by 0x401016: main (StandAlone.cpp:152)
==10570== Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd
==10570== at 0x4C2880D: malloc (vg_replace_malloc.c:236)
==10570== by 0x401475: ReadFileData(char*) (StandAlone.cpp:300)
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570== by 0x401016: main (StandAlone.cpp:152)
EDIT: c++コンパイラでコンパイルできるようにする必要があります。
malloc
.
解決方法は?
これはおかしい。
char**return_data=(char**)malloc(MAX_SOURCE_STRINGS+1);
おそらくそうであるべきです。
char **return_data = malloc ( (MAX_SOURCE_STRINGS+1) * sizeof *return_data );
(となります(便宜上スペースを入れています)。
EDIT
: 若干の補足説明です。
あなたが
return_data[i]=...
に何かを書き込もうとしているのです。
return_data[i]
. では
return_data
は
char**
ということで
return_data[i]
は
char*
. つまり、メモリ上のある場所にポインタを書き込んでいるわけです。
ポインターの長さは8バイトのようですが(これは問題ない)、6バイトしか割り当てられていません。
MAX_SOURCE_STRING+1
. ということは、問題があるのですね。
オフセット 0 に書き込もうとしても、それは問題ではありません。バッファの許容量を超えるデータを書き込もうとしているので、valgrind はそれに対して文句を言っているのです。
この問題を解決するには、ポインタの配列を保持するのに十分な領域を確保する必要があります。各ポインターは
sizeof(char*)
と書くこともできます。
sizeof(*return_data)
または
sizeof *return_data
. したがって、合計で
n * sizeof *return_data
バイトで、ここで
n
は(あなたの場合)マジックナンバーの6です。
関連
-
[解決済み】組み込み関数「malloc」の暗黙の宣言の非互換性
-
[解決済み] (.text+0x20): `main'への未定義の参照と関数への未定義の参照
-
[解決済み】警告:互換性のないポインタ型からの代入
-
[解決済み】式は、単純なポインタ演算を使用して完全なオブジェクト型へのポインタでなければなりません【重複】。
-
[解決済み】Cygwin - Makefile-error: ターゲット `main.o' のレシピに失敗しました。
-
[解決済み】C言語で多重定義を防ぐには?
-
[解決済み】fgetsによるセグメンテーションフォールト(コアダンプ) - と思う。
-
[解決済み] [Solved] .Cファイルをコンパイルしています。アーキテクチャ x86_64 の未定義シンボル
-
[解決済み] Valgrind 無効な free() / delete / delete[] / realloc() in C
-
[解決済み] C言語で配列のサイズを決定するにはどうすればよいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】エラー:cの入力の最後に期待される宣言またはステートメント
-
[解決済み】変数の警告が設定されているが使用されていない
-
[解決済み】エラー:'for'ループの初期宣言はC99モードでしかできない【重複
-
[解決済み】 switch case: error: case label does not reduce to an integer constant
-
[解決済み】C言語でint64_t型を表示する方法
-
[解決済み】未定義参照 makefile が間違っているのかも?
-
[解決済み】C言語のフォーマット文字列でデータ引数が使用されない [重複]。
-
[解決済み】宣言指定子で2つ以上のデータ型がある場合のエラー【非公開
-
[解決済み] Cプログラムで「配列の添え字が整数でない」。
-
[解決済み】c - 警告:関数 'printf'の暗黙の宣言