2009-03-30 5 views
-1

Mein Geist zum Thema Funktionszeiger heute wandert, und ich kam mit dem folgende Szenario in meinem Kopf:Gedankenexperiment mit __stdcall und beschädigten Stapel (C++)

__stdcall int function (int) 
{ 
    return 0; 
} 

int main() 
{ 
    (*(int(*)(char*,char*))function)("thought", "experiment"); 
    return 0; 
} 

AFAIK dieses Code verfälschen würde die stack, also welche Arten von Problemen könnte ich betrachten, wenn ich diesen Code ausgeführt habe?

Ich würde mich selbst untersuchen, aber ich bin für eine Woche von meinem Computer entfernt.

EDIT: Moment mal, ich habe ein bisschen mehr nachgedacht. Wie in den Kommentaren beobachtet wurde, bestand die Absicht dieses Codes darin, einen Parameter auf dem Stapel zu haben, wenn alles gesagt und getan ist (der Aufrufer setzt zwei Params auf den Stack, callee - erwartet nur einen Parameter - springt nur einen aus). Da meine Besetzung die Aufrufkonvention jedoch nicht erwähnt, verwerfe ich zumindest aus der Sicht des Aufrufers stdcall. int function (int) wird immer noch einen Parameter vom Stapel entfernen, aber kehrt der Aufrufer zu der Annahme zurück, dass die Funktion aufgrund der Besetzung __cdecl (der Standard) ist? (d. h. drei Gesamtparameter sind aufgetaucht?)

EDIT2: Die Antwort auf diese zweite Frage, wie von Rob bestätigt, ist ja. Ich hätte neu zu formulieren __stdcall, wenn ich einen param auf den Stapel verlassen wollte:

(*(__stdcall int(*)(char*,char*))function)("thought", "experiment"); 
+0

Die Hauptverfälschung kommt jedoch davon, zwei getrennte Prozessdenken zu haben, sie sollten das Aufräumen machen. – ojblass

+0

Ich wurde für die Ausführung des Codes gewählt ... go figure ... – ojblass

Antwort

2

Sie rufen die Funktion so auf, als wäre es _cdecl, was bedeutet, dass der Aufrufer die Argumente verschiebt und den Stapel aufräumt.

Die Empfangsfunktion ist _stdcall, was bedeutet, dass der Angerufene den Stapel aufräumt. Der Angerufene erwartet ein einzelnes Argument, so dass 4 Bytes vom Stapel verschwinden.

Wenn die Funktion zurückkehrt, wird der Aufrufer zwei Zeiger (die zuvor zwei Zeiger gedrückt haben) abtasten, so dass Ihr Stapel um 4 Bytes beschädigt wird.

Beide Aufrufkonventionen verwenden den gleichen Rückgabe-Mechanismus und haben dieselben Registerregeln (eax, ecx und edx werden nicht beibehalten). Weitere Informationen finden Sie unter wikipedia.

Je nach Layout und Ausrichtung des Stack-Frames kann diese Nichtübereinstimmung eine Reihe von Effekten verursachen. Wenn Sie Glück haben, kommen Sie damit durch. Wenn nicht, könnten Sie die Rücksprungadresse Ihrer Hauptfunktion stören, was das Programm zum Absturz bringt, wenn es zu Wer-weiß-wohin verzweigt. Wenn der Compiler eine Art Stack Guard injiziert hat, um Korruption zu erfassen, wird er dies wahrscheinlich erkennen und das Programm abbrechen.

+0

Ah, also mein Verdacht war in der Tat richtig. Ich müsste __stdcall neu formulieren, wenn ich wollte, dass meine "beabsichtigte Korruption" eintritt (das heißt, dass ein Parameter beibehalten wird, im Gegensatz zu einem zusätzlichen, der abgezogen wird). – GRB

0

ich denke, dass Sie in diesem Fall ‚undefiniert Verhalten‘ haben.

Vom C standard: (Ich würde annehmen, dass es das gleiche in C++ ist)

768 Wenn ein umgebautes Zeiger wird verwendet, um eine Funktion, deren Art zu nennen, ist kompatibel nicht mit dem Spitz zu geben, Das Verhalten ist nicht definiert.

Bearbeiten: Auf den meisten Betriebssystemen würde diese Art von Fehler keine Probleme in Ihrem gesamten Betriebssystem verursachen. Aber es würde zu undefinierten Problemen in Ihrem Programm führen. Es wäre sehr schwierig für ein Benutzerprogramm, einen blauen Bildschirm zu verursachen.

+0

Sicher, aber ich denke, meine Frage ist eher in der Richtung, ob Windows wird Bluescreen, oder ob es mit ihm wie ein einfaches "Deal" char [] Überlauf. Mit anderen Worten, ist diese Art von Fehler ernst genug, um mein System herunterzunehmen? – GRB

+0

aktualisiert mehr Info –

+0

Es ist nichts wert, dass dieses Beispiel über einen falsch-gegossenen Zeiger hinausgeht, da __stdcall bedeutet, dass es der Auftrag der Funktion ist, den Stapel zu löschen. Da die Funktion nur einen Param, einen Int, erwartet, würde sie die beiden an sie gesendeten Parameter vermutlich nicht korrekt löschen. – GRB

1

Nein, es wird definitiv keinen blauen Bildschirm verursachen. Kein User-Mode-Prozess ist dazu in der Lage. Selbst wenn ein solcher Fehler im Kernel-Modus-Code wäre, würde der BSOD nur auftreten, nachdem er auf einen ungültigen Speicher zugegriffen oder falsche Argumente an eine Funktion übergeben hat.

Sie korrumpieren einfach den privaten Speicher Ihres Prozesses, und die Beschädigung kann (oder auch nicht) später zu einer ungültigen Operation führen (z. B. Dereferenzierung eines Zeigers, der auf ungültigen Speicher zeigt). Wenn dies geschieht, beendet das Betriebssystem Ihren Prozess, jedoch nicht früher.