(C++) Wie "Segmentation Fault" ausfindig machen?
*Markus
- sonstiges
1 Hans0 Christian Seiler0 *Markus2 Christian Seiler
Hallo,
Die Kompilierung meines Programms verläuft problemlos. Dummerweise wird aber der Start des Programms durch ein "Segmentation Fault" abgebrochen.
Ich konnte den Fehler auf diese Zeile in main() eingrenzen.
SpriteBase RescuerBase;
/* Es ist diese Zeile darunter */
RescuerBase.setGraphicData("rescuer");
"rescuer" ist übrigens ein gültiges Verzeichnis.
Die Funktion dazu sieht folgendermaßen aus, wobei ich sicherheitshalber auch die indirekt einbezogene Funktion angebe (da ich auf die Variablen dieser Methode zugreife):
class SpriteBase {
public:
int imageWidth;
int imageHeight;
int frameNumbers;
SpriteFrame *animPart;
void setGraphicData(char *dir);
};
void SpriteBase::setGraphicData(char *dir) {
FILE *fp;
char filename[255];
char buffer[255];
char name[255];
int count;
int pause = 0;
sprintf(filename, "%s/info", dir);
if ( (fp=fopen(filename, "r")) == NULL) {
printf("Error opening file %s", filename);
exit(1);
}
fgets(buffer, 255, fp);
sscanf(buffer, "FILES:%d", &frameNumbers);
animPart = new SpriteFrame[frameNumbers];
while (!feof(fp) && count < frameNumbers) {
fgets(buffer, 255, fp);
if (buffer[0] != '\n' && buffer[0] != '\r' && buffer[0] != '\0' && strlen(buffer) != 0) {
sscanf(buffer, "%s %d", name, &pause);
sprintf(filename, "%s/%s", dir, name);
SDL_Surface *temp;
if ( (temp = IMG_Load(filename)) == NULL) {
printf("Couldn't find %s\n", filename);
exit(1);
}
animPart[count].image = SDL_DisplayFormat(temp);
animPart[count].pause = pause;
imageWidth = animPart[count].image->w;
imageHeight = animPart[count].image->h;
count++;
SDL_FreeSurface(temp);
}
}
fclose(fp);
}
Findet jemand diesen Fehler, der einen SegFault auslöst? Ich sehe nämlich offensichtlich den Wald vor lauter Bäumen nicht mehr.
Markus.
Hallo !
SpriteBase RescuerBase;
/* Es ist diese Zeile darunter */
RescuerBase.setGraphicData("rescuer");
vielleicht SpriteBase RescuerBase = new SpriteBase(); // Oder wie auch immer der Constructor der Klasse SpriteBase aussieht.
Ansonsten die Methode setGraphicData Zeile fuer Zeile debuggen. Wenn Du keinen Debugger hast, dann nach jeder Zeile den Inhalt der relevanten Variablen auslesen.
Gruß
Hans
Hallo,
vielleicht SpriteBase RescuerBase = new SpriteBase(); // Oder wie auch immer der Constructor der Klasse SpriteBase aussieht.
Diese Klasse hat keine Konstruktor.
Ansonsten die Methode setGraphicData Zeile fuer Zeile debuggen. Wenn Du keinen Debugger hast, dann nach jeder Zeile den Inhalt der relevanten Variablen auslesen.
Warum ich nicht daran dachte :)
Jedenfalls konnte ich das Problem noch weiter eingrenzen. Es beschränkt sich nun auf folgende Zeilen:
animPart[count].image = SDL_DisplayFormat(temp);
animPart[count].pause = pause;
imageWidth = animPart[count].image->w;
imageHeight = animPart[count].image->h;
In SpriteBase wir "SpriteFrame" als Datentyp verwendet. Hier ist die Struktur dazu:
struct SpriteFrame {
SDL_Surface *image;
int pause;
};
Markus.
Hallo Markus,
animPart[count].image = SDL_DisplayFormat(temp);
animPart[count].pause = pause;
imageWidth = animPart[count].image->w;
imageHeight = animPart[count].image->h;
>
> In SpriteBase wir "SpriteFrame" als Datentyp verwendet. Hier ist die Struktur dazu:
>
> ~~~c
> struct SpriteFrame {
> SDL_Surface *image;
> int pause;
> };
>
ist fuer
animPart[count].image
Speicher angelegt worden ? Oder liefert SDL_DisplayFormat(temp) einen Pointer auf das Bild zurueck ?
Gruß
Hans
Hallo,
animPart[count].image
Speicher angelegt worden ? Oder liefert SDL_DisplayFormat(temp) einen Pointer auf das Bild zurueck ?
Also wenn mich nicht alles täuscht, sollte in der Zeile "animPart = new SpriteFrame[frameNumbers];" genügend Speicher alloziiert worden sein.
Ich wüsste gar nicht, wie ich in diesem Fall Speicher anders alloziieren könnte.
Markus.
Hi !
Probier mal
if (animPart[count].image==NULL)
printf("SDL_DisplayFormat lieferte NULL zurueck !");
bevor Du auf die Komponenten von image zugreifst.
Gruß
Hans
Hallo Hans,
vielleicht SpriteBase RescuerBase = new SpriteBase(); // Oder wie auch immer der Constructor der Klasse SpriteBase aussieht.
new wird in C++ nur bei Zeigern auf Objekte verwendet. Angenommen Du hast eine Klasse TestClass mit dem Konstruktor TestClass(int, int), dann kannst Du folgendes machen:
TestClass obj (2, 5);
TestClass *objp = new TestClass (2, 5);
obj ist dann ein Objekt auf dem Stack, auf das mit obj.eigenschaft / obj.methode zugegriffen wird. objp ist ein Zeiger auf ein Objekt auf dem Heap, auf das mit objp->eigenschaft / objp->methode zugegriffen wird. Dagegen ist
TestClass obj = new TestClass (2, 5);
Quatsch in C++.
Diese Zeile ist also nicht die Ursache für die Segmentation fault, sondern im ursprünglichen Code absolut richtig.
Viele Grüße,
Christian
Hallo Markus,
Findet jemand diesen Fehler, der einen SegFault auslöst?
Auf Anhieb entdecke ich auch nichts, was _zwangsläufig_ zu einer Segfault führt (sehe aber einige Dinge, die jemand zu einem Buffer Overflow ausnutzen könnte, wenn er es darauf anlegt), hast Du schonmal einen Debugger drüber laufen gelassen?
Viele Grüße,
Christian
Hallo,
Auf Anhieb entdecke ich auch nichts, was _zwangsläufig_ zu einer Segfault führt (sehe aber einige Dinge, die jemand zu einem Buffer Overflow ausnutzen könnte, wenn er es darauf anlegt),
Hmmm, wo genau?
hast Du schonmal einen Debugger drüber laufen gelassen?
Mit gdb kenne ich mich zwar nicht so gut aus, aber zuerst prangerte er mir "SDL_DisplayFormat" an, wodurch ich es zur Probe mit "temp" ersetze.
Danach prangerte er die ganze Funktion an.
P.S. Ich muss jetzt leider weg, und kann erst wieder ab 22h weitertesten. Danke einstweil für die Hilfe.
Markus.
Hallo Markus,
Auf Anhieb entdecke ich auch nichts, was _zwangsläufig_ zu einer Segfault führt (sehe aber einige Dinge, die jemand zu einem Buffer Overflow ausnutzen könnte, wenn er es darauf anlegt),
Hmmm, wo genau?
sprintf ist böse (außer Du kannst die Eingabe kontrollieren), da Du nicht angeben kannts, wie groß Dein Puffer ist. Verwende besser snprintf. *scanf solltest Du in Verbindung mit %s nicht verwenden, da Du da auch keine Puffergröße angeben kannst - ich bin mir gerade nicht sicher, ob %255s oder sowas funktioniert, müsstest Du mal nachlesen; wenn nicht, solltest Du Dir eine andere Methode zum Auslesen der Datei heraussuchen. Du kontrollierst frameNumbers nicht nach dem Auslesen, es könnte negativ oder riesig groß sein, deswegen könnte animPart = new SpriteFrame[frameNumbers]; fehlschlagen oder monstermäßig viel Speicher allozieren.
Ah und jetzt sehe ich denke ich auch Deinen Fehler. ;-) Du hast vergessen, count zu initialisieren.
Mit gdb kenne ich mich zwar nicht so gut aus, aber zuerst prangerte er mir "SDL_DisplayFormat" an, wodurch ich es zur Probe mit "temp" ersetze.
Danach prangerte er die ganze Funktion an.
Was meinst Du mit Anprangern? Wie sieht der Stack Trace aus wenn die Segmentation Fault auftritt?
Viele Grüße,
Christian
Hallo,
sprintf ist böse (außer Du kannst die Eingabe kontrollieren), da Du nicht angeben kannts, wie groß Dein Puffer ist. [...]
Da hast du recht. Diese Verschönerungsarbeiten werde ich wohl am Schluss noch erledigen müssen.
Ah und jetzt sehe ich denke ich auch Deinen Fehler. ;-) Du hast vergessen, count zu initialisieren.
Mein Gott. Ja, das war's, danke.
Das Programm macht zwar nicht das, was es soll, aber zumindest macht es jetzt überhaupt etwas. :)
Markus.
Hallo,
ich habe nochmals drüber nachgedacht und frage mich, warum man auf seinem eigenen Computer einen Buffer Overflow erzeugen sollte?
Mein Programm wird nämlich keine Internetverbindung, o.ä. haben.
Markus.
Hallo Markus,
ich habe nochmals drüber nachgedacht und frage mich, warum man auf seinem eigenen Computer einen Buffer Overflow erzeugen sollte?
Mein Programm wird nämlich keine Internetverbindung, o.ä. haben.
Wenn Du Dir bei solchen Programmen schlechten Stil angewöhnst, machst Du bei kritischen Dingen auch so weiter. Wenn Du dagegen hier schon sauber programmierst und aufpasst, dass da (soweit wie möglich) keine Sicherheitslücke drin ist, dann entwickelst Du ein gewisses Auge für solche Dinge und wenn Du dann später Dinge schreibst, die doch am Netz hängen, dann ist die Wahrscheinlichkeit, dass Du bei denen ein riesiges Sicherheitsloch eingebaut haben wirst, deutlich geringer.
Viele Grüße,
Christian
Hallo,
Wenn Du Dir bei solchen Programmen schlechten Stil angewöhnst, machst Du bei kritischen Dingen auch so weiter. Wenn Du dagegen hier schon sauber programmierst und aufpasst, dass da (soweit wie möglich) keine Sicherheitslücke drin ist, dann entwickelst Du ein gewisses Auge für solche Dinge und wenn Du dann später Dinge schreibst, die doch am Netz hängen, dann ist die Wahrscheinlichkeit, dass Du bei denen ein riesiges Sicherheitsloch eingebaut haben wirst, deutlich geringer.
Natürlich. Normalerweise versuche ich ja auch immer möglichst sicher zu programmieren, v.a. wenn das Programm nicht nur für mich selbst ist.
Markus.