fclose()によるセグメンテーション違反
-
22-07-2019 - |
質問
解析中のタブ区切りテキストファイルがあります。最初の列には、 chrX
という形式の文字列が含まれます。ここで、 X
は文字列のセットを示します(例:" 1"、" 2"、...、" X"、" Y"。
これらは、ファイルが解析されるときに、 chromosome
と呼ばれる char *
にそれぞれ保存されます。
テキストファイルは、辞書式に最初の列でソートされます。つまり、「chr1」で始まり、次に「chr2」などで始まる行がいくつかあります。
各" chrX"でエントリ、このエントリに関連付けられている別のファイルを開く必要があります:
FILE *merbaseIn;
// loop through rows...
if (chromosome == NULL)
openSourceFile(&chromosome, fieldArray[i], &merbaseIn, GENPATHIN);
else {
if (strcmp(chromosome, fieldArray[i]) != 0) { // new chromosome
fclose(merbaseIn); // close old chromosome FILE ptr
free(chromosome); // free old chromosome ptr
openSourceFile(&chromosome, fieldArray[i], &merbaseIn, GENPATHIN); // set up new chromosome FILE ptr
}
}
// parse row
次のように定義されている関数 openSourceFile
があります:
void openSourceFile (char** chrome, const char* field, FILE** filePtr, const char *path) {
char filename[100];
*chrome = (char *) malloc ((size_t) strlen(field));
if (*chrome == NULL) {
fprintf(stderr, "ERROR: Cannot allocate memory for chromosome name!");
exit(EXIT_FAILURE);
}
strcpy(*chrome, field);
sprintf(filename,"%s%s.fa", path, field);
*filePtr = fopen(filename, "r");
if (*filePtr == NULL) {
fprintf(stderr, "ERROR: Could not open fasta source file %s\n", filename);
exit(EXIT_FAILURE);
}
}
問題は、次の行でセグメンテーションフォールトが最初の染色体から2番目の染色体( chr1
から chr2
)に移動して終了することです。最初に開いた染色体ファイル:
fclose(merbaseIn);
fclose
にNULLポインターを渡していないのはわかっています。セグメンテーションフォールトまでは、このファイルからデータを読み取っているためです。条件でこれをラップすることもできますが、それでも障害が発生します:
if (merbaseIn != NULL) {
fclose(merbaseIn);
}
さらに、私は openSourceFile
が機能することを知っています(少なくとも chr1
では、 FILE *
の最初のファイルハンドルを設定するとき) chr1
行を解析し、 FILE *
ソースファイルからデータを正しく読み取ります。
セグメンテーションフォールトを発生させているこの fclose
呼び出しについてはどうですか?
解決
valgrind --db-attach=yes --leak-check=yes --tool=memcheck --num-callers=16 --leak-resolution=high ./yourprogram args
セグメンテーション違反は、ローカルの人に影響を与えるものではなく、ヒープのメモリ破損が原因である可能性が非常に高いです。 Valgrind は、最初に行った誤ったアクセスをすぐに表示します。
編集: valgrind
の-db-attach
オプションは、2014年のリリース3.10.0から非推奨になりました。リリースノートの状態:
The built-in GDB server capabilities are superior and should be used
instead. Learn more here:
http://valgrind.org /docs/manual/manual-core-adv.html#manual-core-adv.gdbserver
他のヒント
1つのエラーは次の行にあります:
*chrome = (char *) malloc ((size_t) strlen(field));
これは次のとおりです:
*chrome = (char *) malloc ((size_t) strlen(field)+1);
これは、文字列の末尾に0があり、そのためにスペースを空ける必要があるためです
最良の推測は、コードの他の部分がバッファオーバーランまたは同様のバグによりメモリを破損していることです。
原因ではないが、完全なファイル名が100文字を超えると、ファイル名配列にオーバーラン状態が発生する可能性があります。
デバッガを使用して、merbaseIn変数によって使用されるメモリ位置の変化を監視することをお勧めします。
汎用ポインターの問題
Cは素晴らしい言語ですが、自分の記憶を壊さないことが必要です。 mallocが1バイト短い場合に前述した問題に加えて、他のポインターの問題がある可能性があります。
メモリデバッガの使用をお勧めします。過去には、エレクトリックフェンスはかなり人気がありましたが、最近では valgrindの詳細をご覧ください。他にもたくさんの選択肢があります。
このFILE * filePtrだけで十分な場合、なぜこのFILE ** filePtrなのか? ただの考え...
memcheck
を使用した valgrind
は、セグメンテーション違反の原因を発見するための間違いなく正しいツールです。 valgrind
でデバッガを使用するには、-db-attach
オプションの valgrind
がValgrind 3.10.0のリリース後に廃止されていることに注意してください。 2014.リリースノートの状態:
The built-in GDB server capabilities are superior and should be used
instead. Learn more here:
http://valgrind.org /docs/manual/manual-core-adv.html#manual-core-adv.gdbserver
" malloc" を使用したすべての場所を確認し、間違えたかどうかを確認します。
たとえば、ファイルから読み取った行をchar **に入れていましたが、間違っています malloced as ::
my_list = malloc(sizeof(char) * num_lines_found_in_file);
本来あるべき時:
my_list = malloc(sizeof(char*)* num_lines_found_in_file);