67 Stimmen

Gibt es eine Möglichkeit, dass ein C/C++-Programm vor main() abstürzt?

Gibt es eine Möglichkeit, dass ein Programm vor main() abstürzt?

20voto

conio Punkte 3507

Die Antwort ist einfach: Ja .

Im Einzelnen lassen sich dafür zwei Ursachen unterscheiden. Ich nenne sie Implementierungsabhängig und unabhängig von der Implementierung .

Der eine Fall, der überhaupt nicht von Ihrer Umgebung abhängt ist die der statischen Objekte in C++, die hier erwähnt wurde. Der folgende Code stirbt vor main() :

#include <iostream>

class Useless {
public:
    Useless() { throw "You can't construct me!"; }

};

static Useless object;

int main() {
    std::cout << "This will never be printed" << std::endl;

    return 0;
}

Noch interessanter sind die plattformabhängige Ursachen . Einige wurden hier erwähnt. Eine, die hier ein paar Mal erwähnt wurde, war die Verwendung von dynamisch verknüpften Bibliotheken (DLLs in Windows, SOs in Linux, usw.) - wenn der Lader Ihres Betriebssystems sie lädt, bevor main() können sie dazu führen, dass Ihre Anwendung vor dem main() .

Eine allgemeinere Version dieser Sache ist das Reden über alle Dinge, die den Einstiegspunkt für Ihr Binärprogramm tut, bevor sie Ihr Einstiegspunkt( main() ). Wenn Sie Ihre Binärdatei erstellen, gibt es normalerweise einen ziemlich großen Codeblock, der aufgerufen wird, wenn der Lader Ihres Betriebssystems beginnt, Ihre Binärdatei auszuführen, und wenn er fertig ist, ruft er Ihre main() . Eine häufige Aufgabe dieses Codes ist die Initialisierung der C/C++-Standardbibliothek. Dieser Code kann aus verschiedenen Gründen fehlschlagen (z. B. wegen eines Mangels an Systemressourcen, die er zuzuweisen versucht).

Eine interessante Möglichkeit für eine Binärdatei, Code auszuführen, bevor main() unter Windows ist die Verwendung von TLS-Callbacks (Google wird Ihnen mehr darüber verraten). Diese Technik findet sich normalerweise in Malware als grundlegender Anti-Debugging-Trick (dieser Trick täuschte damals ollydbg, ich weiß nicht, ob er immer noch funktioniert).

Der Punkt ist, dass Ihre Frage eigentlich gleichbedeutend ist mit "gibt es eine Möglichkeit, dass das Laden einer Binärdatei dazu führt, dass der Benutzercode vor dem Code in main() ?", und die Antwort lautet Verdammt, ja!

11voto

nategoose Punkte 11636

Jedes Programm, das sich darauf verlässt, dass gemeinsam genutzte Objekte (DLLs) vor main geladen werden, kann vor main fehlschlagen.

Unter Linux wird der Code in der dynamischen Linker-Bibliothek (ld-*.so) ausgeführt, um alle abhängigen Bibliotheken weit vor dem Hauptprogramm bereitzustellen. Wenn benötigte Bibliotheken nicht gefunden werden können, keine Zugriffsrechte haben, keine normalen Dateien sind oder ein Symbol nicht enthalten, von dem der dynamische Linker, der Ihr Programm gelinkt hat, dachte, dass es vorhanden sein sollte, als er Ihr Programm gelinkt hat, kann dies zu Fehlern führen.

Außerdem kann jede Bibliothek beim Verknüpfen einen Teil des Codes ausführen. Dies liegt vor allem daran, dass die Bibliothek möglicherweise weitere Bibliotheken verlinken oder einige Konstruktoren ausführen muss (selbst in einem C-Programm könnten die Bibliotheken C++ oder etwas anderes enthalten, das Konstroktoren verwendet). Darüber hinaus haben Standard-C-Programme bereits die stdio-DATEIEN stdin, stdout und stderr angelegt. Auf vielen Systemen können diese auch geschlossen werden. Dies impliziert, dass sie auch free()ed werden, was bedeutet, dass sie (und ihre Puffer) malloc()ed wurden, was fehlschlagen kann. Es deutet auch darauf hin, dass mit den Dateideskriptoren, die diese FILE-Strukturen repräsentieren, irgendetwas anderes gemacht wurde, was ebenfalls fehlschlagen kann.

Andere Dinge, die möglicherweise passieren könnten, wären, wenn das Betriebssystem die Einrichtung der Umgebungsvariablen und/oder der Befehlszeilenargumente, die an das Programm übergeben wurden, durcheinander bringen würde. Der Code vor main musste wahrscheinlich etwas mit diesen Daten machen, bevor er main aufrief.

Viele Dinge passieren vor dem Haupttermin. Jeder von ihnen kann auf fatale Weise versagen.

5voto

Matthieu M. Punkte 266317

Es gibt viele Möglichkeiten.

Zunächst müssen wir verstehen, was eigentlich vor der Ausführung von main passiert:

  • Laden von dynamischen Bibliotheken
  • Initialisierung von Globals
  • Bei einigen Compilern können einige Funktionen explizit ausgeführt werden

All dies kann auf verschiedene Weise zu einem Absturz führen:

  • das übliche undefinierte Verhalten (Dereferenzierung von Null-Zeigern, Zugriff auf Speicher, den man nicht verwenden sollte...)
  • eine Ausnahme ausgelöst > da es keine catch , terminate aufgerufen wird und das Programm endet

Das ist natürlich sehr ärgerlich und möglicherweise schwer zu debuggen, und deshalb sollte man davon absehen, Code auszuführen, bevor main und bevorzugen, wenn möglich, eine träge Initialisierung oder eine explizite Initialisierung innerhalb von main .

Wenn es sich um eine DLL handelt, die versagt und die man nicht ändern kann, ist das natürlich ein großes Problem.

2voto

Zoli Punkte 1127

Ein etwas erfundenes Beispiel wäre:

int a = 1;
int b = 0;
int c = a / b;

int main()
{
    return 0;
}

Es ist unwahrscheinlich, dass du so etwas jemals tun wirst, aber wenn du viel Makromagie betreibst, ist es durchaus möglich.

2voto

smocoder Punkte 226
class Crash
{
public:
  Crash( int* p )
  { *p = 0; }
};

static Crash static_crash( 0 );

void main()
{
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X