fclose () che causa un errore di segmentazione
-
22-07-2019 - |
Domanda
Ho un file di testo delimitato da tabulazioni che sto analizzando. La sua prima colonna contiene stringhe del formato chrX
, dove X
indica una serie di stringhe, ad es. & Quot; 1 " ;, " 2 " ;, ..., " X "," "Y".
Questi sono memorizzati ciascuno in un char *
chiamato cromosoma
, mentre il file viene analizzato.
Il file di testo è ordinato lessicograficamente sulla prima colonna, cioè avrò un numero di righe che iniziano con " chr1 " ;, e quindi " chr2 " ;, ecc.
Ad ogni " chrX " voce, devo aprire un altro file associato a questa voce:
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
Ho la funzione openSourceFile
che è definita come segue:
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);
}
}
Il problema è che la mia applicazione si chiude con un errore di segmentazione che va dal primo cromosoma al secondo (da chr1
a chr2
) nella riga seguente, dove chiudo il primo file cromosomico che ho aperto:
fclose(merbaseIn);
So che non sto passando a fclose
un puntatore NULL, perché fino all'errore di segmentazione, sto leggendo i dati da questo file. Posso anche avvolgerlo in un condizionale e ottengo ancora l'errore:
if (merbaseIn != NULL) {
fclose(merbaseIn);
}
Inoltre, so che openSourceFile
funziona (almeno per chr1
, quando si configura il primo handle di file di FILE *
) perché la mia applicazione analizza le righe chr1
e legge correttamente i dati dal file sorgente FILE *
.
Che cos'è questa chiamata fclose
che sta causando un errore di segmentazione?
Soluzione
valgrind --db-attach=yes --leak-check=yes --tool=memcheck --num-callers=16 --leak-resolution=high ./yourprogram args
È molto probabile che il segfault sia causato dalla corruzione della memoria nell'heap, non da qualsiasi cosa colpisca la gente del posto. Valgrind ti mostrerà immediatamente il primo accesso sbagliato che hai effettuato.
Modifica: l'opzione --db-attach
su valgrind
è stata deprecata dalla versione 3.10.0 nel 2014. Le note sulla versione indicano:
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
Altri suggerimenti
un errore che noto è questa riga:
*chrome = (char *) malloc ((size_t) strlen(field));
che dovrebbe essere:
*chrome = (char *) malloc ((size_t) strlen(field)+1);
Questo perché una stringa ha uno 0 di chiusura alla fine del quale devi anche fare spazio
La migliore ipotesi è che un'altra parte del codice stia danneggiando la memoria attraverso un sovraccarico del buffer o un bug simile.
Sebbene sia improbabile che sia la causa, hai una potenziale condizione di superamento nell'array del nome file quando il nome file completo supera i 100 caratteri.
Suggerirei di utilizzare un debugger per controllare le modifiche nella posizione della memoria utilizzata dalla variabile merbaseIn.
Problema puntatore generico
C è un linguaggio eccezionale ma richiede di non ostruire la tua memoria. Oltre al problema precedentemente notato in cui il malloc è corto di 1 byte, potresti avere altri problemi con il puntatore.
Suggerirei utilizzando un debugger di memoria . In passato, Electric Fence era piuttosto popolare, ma oggigiorno leggi di più su valgrind . Ci sono molte altre scelte.
Oltre all'errore riscontrato da reinier , sospetto che:
free(chromosome);
dovrebbe essere seguito da:
chromosome = NULL;
al fine di prevenire il potenziale utilizzo di un valore non più valido.
perché questo filePtr FILE ** se solo questo filePtr FILE * fosse sufficiente? solo un pensiero ...
valgrind
con memcheck
è sicuramente lo strumento giusto per scoprire la causa dell'errore di segmentazione. Per usare un debugger con valgrind
, nota che l'opzione --db-attach
su valgrind
è stata deprecata da quando Valgrind 3.10.0 è stato rilasciato in 2014. Le note di rilascio indicano:
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
Esamina tutti i luoghi che hai utilizzato " malloc " e verifica se hai commesso un errore.
Ad esempio, stavo inserendo righe lette da un file in un carattere **, ma in modo errato lo ha ingannato come:
my_list = malloc(sizeof(char) * num_lines_found_in_file);
Quando avrebbe dovuto essere:
my_list = malloc(sizeof(char*)* num_lines_found_in_file);