# [C] - fclose() verursacht segmentation fault ?!



## KAEPS133 (25. November 2015)

Hey,

ich stehe grade irgendwie total auf dem Schlauch und könnte grade mal etwas Hilfe benötigen. Ich muss für die Hochschule eine einfache Virtuelle Maschine programmieren. Läuft soweit alles wunderbar, nur beim einlesen einer Binärdatei gibt es ein paar Probleme. Um genauer zu sein beim Aufruf von fclose(). Sobald ich fclose() aufrufe wird unter Ubuntu ein *Segmentation fault (core dump)* geworfen und und ende ist. Unter Windows läuft alles problemlos durch, kommentiere ich fclose() aus läuft es auch unter Ubuntu normal durch, nur das die Datei eben nicht geschlossen wird. Und da das alles unter irgend einer Linux-Distribution getestet wird, ist das natürlich nicht so ideal. 

Ich steh aber grade komplett auf dem Schlauch und will den Fehler einfach nicht finden.
Hier mal ein ausschnitt vom Code:

```
void openBin(char *fileName) {
     /*Variablen*/


    binFile = fopen(fileName, "rb");


    if (!binFile)
    {
        error("Unable to open file!"); /*beim Aufruf von error wird auch exit(1) aufgerufen*/
    }


     /*Speicherreservierung mit malloc und dem anschließenden lesen aus der Datei*/

    if (fclose(binFile) != 0) {
        error("Warning ! Couldn't close the file.\n");
    }
}
```

Wäre klasse wenn mir jemand vom Schlauch runter helfen könnte!


----------



## DKK007 (25. November 2015)

Kann es sein, das du auf einen falschen Speicherbereich zugreifst.


----------



## KAEPS133 (25. November 2015)

Aber dann dürfte das Programm doch nicht korrekt durchlaufen wenn das fclose() nicht aufgerufen wird. Dürfte also eigentlich nicht sein, aber ich prüfe es noch mal.

Das ist halt irgendwie das komische das alles perfekt funktioniert wenn es kein fclose() gibt. Aber sobald ein fclose() erreicht wird commt ein segmentation fault.


----------



## bingo88 (25. November 2015)

Wenn der Dateideskriptor irgendwie verbastelt wird, dann merkst du das erst beim fclose(). Ohne den restlichen Code (malloc, fread, etc) zu kennen, würde ich auch auf ein Speicherzugriffsproblem tippen. Eventuell binFile überschrieben?


----------



## Malkolm (25. November 2015)

Der wahrscheinlichste Fall eines segmentation fault bei fclose ist fclose(NULL).
Baue testweise mal ein if(binFile!=NULL) fclose(binFile); ein und schaue ob das Programm noch crasht.
Ohne weiteren Code ist der genaue Fehler nicht einzugrenzen.


----------



## KAEPS133 (25. November 2015)

if(binFile!=NULL) fclose(binFile); hat leider nichts geändert. Wirklich viel vom Code posten kann ich leider nicht da das irgendjemand anders aus dem Kurs hier finden könnte, Kopiert und ich dann Plagiatsmist an der backe habe 

So vom Prinzip läuft das:

```
binFile = fopen(fileName, "rb");
buffer_int = (int*)malloc(sizeof(int)*ftell(binFile));
fread(buffer_int, 1, 4, binFile);
codeSize = buffer_int[0];

fread(buffer_int, 1, codeSize * 4, binFile);
for (value = 0; value < codeSize; value++) {
 /*hier wird aus buffer_int[value] die werte gelesen*/
}
```


----------



## DOcean (25. November 2015)

mach mal folgendes

nur fopen und gleich danach fclose -> wenns geht dann ein Element nach dem anderen
dazukopieren und gucken wann es knallt


----------



## bingo88 (25. November 2015)

ftell() liefert (im Falle von Binärdateien) die Anzahl der Bytes vom Anfang der Datei bis zur aktuellen Position des Lesezeigers. Wenn du die Datei gerade öffnest, ist dieser Lesezeiger bei 0, d.h. ftell müsste 0 liefern. Das geht dann in dein malloc. Du müsstest zuvor mit fseek(binFile, 0, SEEK_END) das Ende der Datei suchen und danach mit fseek und SEEK_SET wieder zurück an den Anfang gehen.


----------



## KAEPS133 (26. November 2015)

Ok ich glaube ich bin vom Schlauch runter. Es lag wirklich am malloc.


```
binFile = fopen(fileName, "rb");
buffer_int = (int*)malloc(sizeof(int));
fread(buffer_int, 1, 4, binFile);
codeSize = buffer_int[0];

buffer_int = (int*)malloc(codeSize);


fread(buffer_int, 1, codeSize * 4, binFile);
for (value = 0; value < codeSize; value++) {
 /*hier wird aus buffer_int[value] die werte gelesen*/
}
```

Die Größe der Datei (codeSize) steht ja neben ein paar anderen Informationen am in den ersten 16 Bytes der Datei. So klappt es jetzt Problemlos.
Manchmal ist man echt verdammt doof  

Danke für eure Hilfe!


----------



## bingo88 (26. November 2015)

Ich hab das mal im code kommentiert:

```
int codeSize;
int *buffer_int;

/*
 * Ein paar Konsistenzprüfungen wären auch nicht verkehrt:
 * codeSize > 0? codeSize < Dateigröße?
 *
 * Achtung: sizeof(int) muss nicht immer 4 sein ;-)
 * Ich gebe das hier an, damit man die Parameter von fread() nachvollziehen kann:
 * fread(<Speicher>, <Bytes pro Element>, <Anzahl Elemente>, <Dateihandle>)
 *
 * fread() liefert die Anzahl der gelesenen Elemente zurück. Wenn die ungleich der
 * angefragten Anzahl ist, gab es einen Lesefehler (End of file, ...).
 */
if (fread(&codeSize, sizeof(int), 1, binFile) != 1)
{
    /* Fehler beim Lesen ... */
}

/*
 * Ist codeSize = Anzahl der ints oder in Bytes?
 * Die folgende Implementierung wäre für codeSize = Anzahl ints richtig.
 * Der Cast ist bei einem reinen C-Compiler übrigens optional.
 *
 * calloc(<Anzahl Elemente>, <Bytes pro Element>) =
 * malloc(<Anzahl Elemente> * <Bytes pro Element>)
 */
buffer_int = (int*)calloc(codeSize, sizeof(int));

if (fread(buffer_int, sizeof(int), codeSize, binFile) != codeSize)
{
    /* siehe oben */
}

for (value = 0; value < codeSize; value++) {
    /*
     * Das sieht für mich nach codeSize = Anzahl ints aus, in dem Fall wäre dein
     * malloc falsch: buffer_int = malloc(codeSize) würde codeSize Bytes allozieren,
     * das entspräche dann einem int-Array mit (codeSize / 4) Elementen.
     *
     * Dein zweites fread dürfte eigentlich dann auch nicht funktionieren, da du
     * dann den allozierten Speicher überschreitest:
     * fread(buffer_int, 1, codeSize * 4, binFile) => Lese 1 * codeSize * 4 Bytes,
     * du hast aber nur ein Array mit codeSize Bytes angelegt. Wenn die Datei vorher
     * zu Ende ist, macht sich das nicht durch einen Speicherzugriffsfehler
     * bemerkbar. Der Rückgabewert würde da einen Hinweis liefern.
     */
     
    /* hier wird aus buffer_int[value] die werte gelesen */
}
```


----------



## KAEPS133 (27. November 2015)

Danke für die Antwort. Codesize könnte ich zwar noch Prüfen, die gelesenen Daten werden aber von einem Compilier erstellt der die CodeSize  in die Datei schreibt.

So stehts in der Beschreibung des Dateiformates:



> 4 bytes        number of instructions contained in the file -> Codesize
> 
> n * 4 bytes    instructions (the program to be executed)




Da ist noch eine ganze menge anderer Prüfungen für die Gültigkeit im Code vorhanden -> aufgrund von dem ganzen Plagiatswahnsinn muss ich die hier leider raus lassen.


----------



## bingo88 (27. November 2015)

Dann ist int *buff_int = malloc(codeSize) definitiv falsch. Eine Instruktion besteht aus 4 Bytes und codeSize gibt die Anzahl der Instruktionen an. malloc() muss also mit 4 * codeSize aufgerufen werden, da malloc() die Anzahl Bytes erwartet. In C++ könntest du int array[] = new int[codeSize] schreiben, das geht in C aber nicht, da muss man die Länge des Datentyps explizit mit einrechnen. Und natürlich das anschließende Freigeben des Speichers mittels free() nicht vergessen.


----------

