NULL-Ptr dereferenzieren
-
Hallo,
ich hab vor kurzem mal wieder ein bisschen rumgespielt und war erstaunt, das folgendes problemlos funktioniert.
class Test { public: Test() : bValue_(true); bool IsAlwaysTrue(void){ return true; } bool IsTrue(void){ return bValue_; } private: bool bValue_; }; Test *pTest = 0; pTest->IsAlwaysTrue();//no Problem pTest->IsTrue();//crashMeine Erklärung, warum IsAlwaysTrue nicht abstürzt wäre, weil es ein MFP ist, der nicht au resourcen zugreift. Somit wird es eigentlich behandelt, wie eine static-function.
Wenn so ein Null Ptr-MFP Aufruf also crasht, dann also nur, wenn auf Speicher von membern zugegriffen wird, die es ja gar nicht giebt.Hab ich das so erstmal richtig verstanden? Sollte man also nicht prinzipiell static schreiben, bei Funktionen, die nicht auf member zugreifen, auch wenn man sie nicht als static aufgerufen werden sollen, um diesen Fakt kenntlich zu machen?
-
Nein das ist beides undefiniert und es kann passieren was will.
-
Das ist mirklar, war aber auch nicht die Frage. Brauchst nicht zu denken, das ich solchen code schreiben würde
. Ist mir nur vor kurzem beim Debuggen von Fremdcode über den weg gelaufen und ich hab mich gefragt, warum das nicht crasht.Das setzt übrigens der VC und der g++ genauso um. Wie soll das der Compiler auch abfangen: am ende kommt ein call zu einer Adresse raus und der ist ja OK.
-
Mach mal aus deiner Klasse eine polymorph-fähige Klasse. Sprich mach mal eine der Memberfunktionen virtual, oder den Destruktor. Dann dürfte es nicht mehr funktionieren. Weil dann die VTable benötigt wird. (ist jetzt meine Vermutung)
Bei Klassen die nicht polymorph sind, sind es ja ganz normale Funktionen und Structs... so salopp gesagt.
Ich kanns hier aber nicht ausprobieren, erst zu Hause.
-
TheBigW schrieb:
am ende kommt ein call zu einer Adresse raus und der ist ja OK.
Das ist so nicht richtig. Es kommt sowas raus wie:
bool Test_IsAlwaysValid( Test* this) { return true; } bool Test_IsTrue( Test* this) { return *(this + OffSetVonbValue_); ///< tödlich }Was auch erklärt, warum ersteres nicht crasht. Mit MeberFunctionPointers hat das meiner Meinung nach nichts zu tun (das Member steht ja schon fest (IsAlwaysValid oder IsTrue), wir haben keinen Zeiger darauf).
-
Warum soll das auch nicht funktionieren. Dazu müsste der Compiler ja extra überprüfen, ob der Zeiger Null ist oder nicht. Aber warum sollte er, er verlässt sich einfach darauf, dass du ihm sowas nicht unterschiebst, weil du nicht von undefiniertem Verhalten abhängig sein willst.
Im Debug-Modus ist es dagegen IMO durchaus denkbar, das sowas überprüft wird.
-
Ich denke ich werde das wirklich mal eingehend mit einer Klasse mit virtuellen Funktionen testen und auch mal durch den disassembler jagen.
@7H3 N4C3R
Ist ja in etwa das was ich dachte: der Funktionsaufruf klappt immer, erst beim Resourcenzugriff kracht es, durch die Berechnug des Offsets auf this.
eben, wer solchen Code schreibt hat es verdient, das er ihm um die Ohren fliegt und genau das hätte ich als ich das das erste mal gesehn habe eigentlich auch erwartet
