Virtuelle Methode einer Klasse in vTable austauschen?



  • Hallo zusammen,

    Ich weiss inzwischen, dass die Sache mit der vTable Compilerabhängig ist und solche Geschichten zu nicht-portierbaren Code führen können. Das ist aber auch nicht meine Absicht. Ich möchte nur Verstehen Lernen, wie das Ganze so funktionieren kann.

    Ich verwende dazu VS10 Express.

    Definiert habe ich eine Klasse CDrawObject

    class CDrawObject
    {
    public:
    	CDrawObject(void);
    	virtual ~CDrawObject(void);
    	virtual void draw(HDC hdc, PAINTSTRUCT* ps);
    };
    

    Um an den vTable Eintrag für die Memberfunktion 'draw' zu kommen, erzeuge ich zunächst eine Globale Instanz der Klasse und lasse mir den Pointer auf die vTable zurück geben:

    CDrawObject Zeichnen;
    
    // in WinMain dann ...
    CDrawObject* pToInstance = &Zeichnen;
    int* vTablePtr = (int*)((int*)pToInstance)[0];
    

    Im Debugger sieht man nun, dass sich der virtuelle Class Destructor auf Intex '0' und die virtuelle Funktion 'draw' auf dem Index '1' befinden. So Weit so Gut. Nun benötige ich die Austausch Funktion und die dazu passende Signatur und ab dem Punkt wird es für mich schwierig:

    void DummyFunktion(HDC hdc, PAINTSTRUCT* ps);			// Austausch Funktion
    typedef void (*pZEICHENFUNC)(HDC hdc, PAINTSTRUCT* ps);	// Funktions Typ/Signatur
    pZEICHENFUNC pOriginalFunktion = NULL;					// Sichert Adresse der Klassen Funktion 'draw'
    
    // in WinMain dann der Austausch ..
    	// Sichern der Adresse der Original Funktion
    	pOriginalFunktion = (pZEICHENFUNC)vTablePtr[1];
    
    	// Kopieren der Adresse der Austausch-Funktion an die Stelle von 'draw'
    	DWORD dwOldProt;
    	VirtualProtect(&vTablePtr[1], sizeof(int), PAGE_EXECUTE_READWRITE, &dwOldProt);
    	vTablePtr[1] = (int)DummyFunktion;
    	VirtualProtect(&vTablePtr[1], sizeof(int), dwOldProt, NULL);
    

    Nun zu meinen Fragen:

    1.)
    Ich kann im Debugger sehen, wie die DummyFunktion (auch) bei der bereits exitierenden Instance 'Zeichnen' die ursprüngliche 'draw' Funktion ersetzt.
    Aber der Aufruf 'Zeichnen.draw(...)' führt wieder die original Funktion aus. Eine NACH dem Austausch erzeugte Instanz 'CDrawObject neueInstanz = new CDrawObject();*' führt dann bei 'neueInstanz->draw(...)' wie erwartet die DummyFunktion aus.
    Das verstehe ich nicht. Warum benutzt die Instanz Zeichnen nicht die DummyFunktion?

    2.)
    Die DummyFuntion wird zwar ausgeführt und zeichnet auch, aber das Programm crasht dann wenn die DummyFunktion beendet wird mit der Meldung:

    Run-Time Check Failure #0 - The value of ESP was not properly saved across a
    function call.  This is usually a result of calling a function declared with one
    calling convention with a function pointer declared with a different calling
    convention.
    

    Die Funktions Signatur passt natürlich perfekt zur DummyFunktion aber wohl nicht zur Class Member Function.
    Also meine Frage: Kann ich die Klassen Methode überhaupt zur Laufzeit austauschen? Wenn ja, wie muss die Signatur dann aussehen?

    Grüße,
    mathi

    Edit: Objective-C Tags durch C++ Tags ersetzt.



  • Ad 1.) Zeig mal deinen kompletten Code. Da kann einiges mit reinspielen. Ich würde mal behaupten du musst da einige Barriers reinmachen und solltest idealerweise dafür sorgen dass der Instruction-Cache geflushed wird.

    ps: Und du musst natürlich dafür sorgen dass der Compiler den "virtual call" nicht wegoptimieren kann. In deinem Beispiel kann er das, weil er ja sieht dass der konkrete Typ des Objekts ganz sicher CDrawObject ist.

    Ad 2.) Die Funktion muss natürlich die selbe Signatur haben, also inklusive des versteckten "this" Parameters. Wie man das am einfachsten macht weiss ich aber auf die Schnelle so nicht. Die Sache ist nämlich, du musst auch die __thiscall Calling-Convention verwenden, und die deckt sich weder mit __stdcall noch mit __cdecl.
    Du könntest natürlich eine Member-Funktion einer Dummy-Klasse verwenden, und dann das Dummy-this nach CDrawObject* casten. Nur wie man dann an die Adresse der Dummy-Memberfunktion rankommt ... pfuh. Klar, du kannst nen Zeiger auf das Ding mit &Klasse::Funktion machen, nur das ist dann halt ein Member-Function-Pointer, und wie die genau aussehen ist leider total Compiler-spezifisch.

    Wenn du nur rumspielst kannst du natürlich die Calling-Convention der Original-Funktion anpassen z.B. auf __stdcall . Dann musst du in der Dummy-Funktion nur nen zusätzlichen Parameter CDrawObject* thisPtr dazumachen (als ersten Parameter!), und diese Funktion ebenfalls __stdcall machen. Das sollte auf jeden Fall klappen, denn genau so ruft C-Code auch COM Funktionen über den vTable auf.

    ----

    Und wieso verwendest du Objective-C Tags? Objective-C und C++ sind zwei GANZ unterschiedliche Tiere, und das was du verwendest ist C++.



  • Zu 1)
    Greift die vTable-Geschichte nicht eh nur bei Zeigern und Referenzen?



  • Für __thiscall wird deine Funktion zu __fastcall und nach dem ersten Parameter gibts noch nen useless Dummyparameter.



  • KN4CK3R schrieb:

    Für __thiscall wird deine Funktion zu __fastcall und nach dem ersten Parameter gibts noch nen useless Dummyparameter.

    Hihi, daran hätte ich jetzt nicht gedacht. Das ist reichlich pervers, sollte aber funktionieren. Natürlich nur für nicht-vararg Funktionen, aber wer braucht schon vararg Funktionen 😉

    @Caligulaminus
    Im Prinzip ja.

    Die "vTable-Geschichte" greift immer wenn sich der Compiler nicht sicher ist um welche konkrete Klasse es sich handelt. Wenn man "direkt" auf eine Instanz eine Funktion aufruft, dann müsste der Compiler schon ziemlich doof sein damit es nicht greift.
    Andrerseits ist aber bei nem Zeiger bzw. ner Referenz nicht sichergestellt dass der Compiler über den vTable geht. Er kann ja in vielen Fällen trotzdem genau wissen um welchen konkreten Typ es sich handelt (static analysis und so).



  • hustbaer schrieb:

    und solltest idealerweise dafür sorgen dass der Instruction-Cache geflushed wird.

    Wo ich nochmal drüber nachdenke... das wird hier vermutlich nichtmal nötig sein. Weil ja nicht direkt in den vTable reingesprungen wird, sondern nur ein Zeiger als "Datum" aus dem vTable geladen, "über" den die Funktion dann angesprungen wird.

    Und der Datencache sieht ja sowieso was abgeht.



  • moin,

    vielen Dank für euere Antworten!

    Also zu 1.)
    Da lagt ihr richtig ... Habe das Initial Object, um an die vTable zu kommen nun dynamisch erzeugt, und siehe da, die DummyFunktion wir auch dort sofort verwendet.

    Zu 2.)
    Ja der Source Code, dann könntet ihr auch direkt Code Posten für die Lösungsidee. Da steht noch viel Testmüll drinn, daher hatte ich den auch nur verkürzt gepostet. folgt aber, sobald ich den "geputzt" habe.

    Vielen Dank soweit,
    mathi



  • Also hier nun der Source.
    Einmal komplett als VC++10 sln ... Edit:link entfernt

    und zum direkt lesen, aber trotzdem ohne den Standard WIN 32 kram.
    (Ist "10mal" so viel code, als der code, um den es geht.) Wenn der
    trotzdem sein muss, sagts bitte einfach nochmal.

    Meine Klasse:

    // DrawObject.h
    #pragma once
    
    class CDrawObject
    {
    public:
    	CDrawObject(void);
    	virtual ~CDrawObject(void);
    	virtual void draw(HDC hdc, PAINTSTRUCT* ps);
    };
    
    // DrawObject.cpp
    #include "StdAfx.h"
    #include "DrawObject.h"
    
    CDrawObject::CDrawObject(void)
    {
    }
    
    CDrawObject::~CDrawObject(void)
    {
    }
    
    void CDrawObject::draw(HDC hdc, PAINTSTRUCT* ps)
    {
    	HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, CreateSolidBrush(RGB(10,120,220)));
    	RoundRect(hdc, 100, 100, 200, 200, 30, 30);
    	DeleteObject(SelectObject(hdc, hOldBrush));
    }
    
    // VTableSample.cpp : Definiert den Einstiegspunkt für die Anwendung.
    //
    
    #include "stdafx.h"
    #include "VTableSample.h"
    #include "DrawObject.h"
    
    // [...]
    
    CDrawObject* pZeichnen;
    typedef void (*pZEICHENFUNC)(HDC hdc, PAINTSTRUCT* ps);
    pZEICHENFUNC pOriginalFunktion = NULL;
    void DummyFunktion(HDC hdc, PAINTSTRUCT* ps);
    
    int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
    {
    	// [... Fenster Klasse registrieren ...]
    
    	// Austauschen der Funktion
    	pZeichnen = new CDrawObject();
    	int* vTablePtr = (int*)((int*)pZeichnen)[0];
    
    	// Sichern der Adresse der Original Funktion
    	pOriginalFunktion = (pZEICHENFUNC)vTablePtr[1];
    
    	// Kopieren der Adresse der DummyFunktion an die Stelle von 'draw'
    	DWORD dwOldProt = 0;
    	VirtualProtect(&vTablePtr[1], sizeof(int), PAGE_EXECUTE_READWRITE, &dwOldProt);
    	vTablePtr[1] = (int)DummyFunktion;
    	VirtualProtect(&vTablePtr[1], sizeof(int), dwOldProt, NULL);
    
    	// Anwendung initialisieren, Fenster erstellen
    	// Hauptnachrichtenschleife:
    	// Nachrichtenschleife beendet, Fenster zerstört
    
    	delete pZeichnen;
    
    	return (int) msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	// [...]
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, &ps);
    		// TODO: Hier den Zeichnungscode hinzufügen.
    		{
    			pZeichnen->draw(hdc, &ps);
    		}
    		EndPaint(hWnd, &ps);
    		break;
    	// [...]
    }
    
    void DummyFunktion(HDC hdc, PAINTSTRUCT* ps)
    {
    	HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, CreateSolidBrush(RGB(200,0,0)));
    	RoundRect(hdc, 250, 100, 350, 200, 30, 30);
    	DeleteObject(SelectObject(hdc, hOldBrush));
    	// vorm return stoppen, zum prüfen, was gezeichnet wurde
    	::MessageBoxA(NULL, "Rotes Rect = DummyFunktion\nBlaues Rect = OriginalFunktion", "Warten ...", MB_OK); 
    }
    


  • mathi schrieb:

    und zum direkt lesen, aber trotzdem ohne den Standard WIN 32 kram.
    (Ist "10mal" so viel code, als der code, um den es geht.) Wenn der
    trotzdem sein muss, sagts bitte einfach nochmal.

    Hihi.
    Ich dachte du willst "nur mal testen".
    Will uns hier denn jeder nur mehr verarschen?
    Schreib doch einfach dass du irgend ein Programm hacken/patchen/... willst.

    ps: Das ist immer noch kein lauffähiges Beispiel, die Funktion wird da ja nirgends aufgerufen. Ausserdem fehlt die stdafx.h. Und es ist nicht nur nicht genug da, sondern gleichzeitig auch viel zu viel.
    Dass da in dem Programm wo du das anwenden willst mit Fenstern rumgemacht wird, interessiert ja für die Frage "wie tu ich vtable patchen" nicht.
    Das kann man mit einem viel einfacheren Beispiel erschlagen.



  • nabend hustbaer,

    hustbaer schrieb:

    Hihi.
    Ich dachte du willst "nur mal testen".
    Will uns hier denn jeder nur mehr verarschen?

    Warum sollte das kein Test sein? Da wo ich hin will, steht doch (noch) garnicht zur Diskussion. Die vTable zu manipulieren ist meine Absicht und der Code hier ist mein Test dazu. Mit dem Verarschen tust du mir Unrecht. Ich habe mein aktuelles Problem genau auf den Punkt reduziert, an dem ich fest stecke und hier ohne schnörkel, Verzierungen und Sonstigem Overhead formuliert. Falls du dich daher fragst was ich vor habe und neugierig geworden bist, dann kann das doch nur positiv sein. Dann beschäftigen sich offensichtlich Leute mit diesem Thread und ich habe höhere Chancen, mein Problem zu lösen. Aber mit verarschen hat das nichts zu tun.

    hustbaer schrieb:

    Schreib doch einfach dass du irgend ein Programm hacken/patchen/... willst.

    Naja, im Prinzip stehts doch schon im Titel. Wenn ich jemanden Frage, wie ich ein Auto fahre, dann laber ich ihn doch nicht gleich damit zu, wo ich überall hinfahren möchte.

    Wieder zum Thema:

    hustbaer schrieb:

    ps: Das ist immer noch kein lauffähiges Beispiel, die Funktion wird da ja nirgends aufgerufen. Ausserdem fehlt die stdafx.h.

    Hast du da evtl. den Link oben zum kompletten Project/Source übersehen?
    Die Funktion wird auch aufgerufen. Den Teil der WndProc mit der WM_PAINT Behandlung habe ich gepostet.
    Die stdafx.h habe ich tatsächlich vergessen. Hier als Nachtrag:

    // stdafx.h
    #pragma once
    
    #include "targetver.h"
    
    #define WIN32_LEAN_AND_MEAN // Selten verwendete Teile der Windows-Header nicht einbinden.
    // Windows-Headerdateien:
    #include <windows.h>
    
    // C RunTime-Headerdateien
    #include <stdlib.h>
    #include <malloc.h>
    #include <memory.h>
    #include <tchar.h>
    
    ///////////////////////////////////////////////
    
    // targetver.h
    #pragma once
    
    #include <SDKDDKVer.h>
    

    Einen schönen Abend euch allen!
    mathi

    Auch noch ein PS.:

    hustbaer schrieb:

    Und es ist nicht nur nicht genug da, sondern gleichzeitig auch viel zu viel. Dass da in dem Programm wo du das anwenden willst mit Fenstern rumgemacht wird, interessiert ja für die Frage "wie tu ich vtable patchen" nicht.

    Zu viel, zu wenig? Du hast um den Source gebeten. Der Fenster kram ist raus, das Framework ist zu erkennen. Komplett Projekt ist verlinkt ... Was mach ich Falsch? Oder anders gefragt, womit ecke ich bei dir an?



  • Ne guck mal Freund, du schreibst "Ich möchte nur Verstehen Lernen, wie das Ganze so funktionieren kann.".

    Und dann ein paar Beiträge weiter was von Code der 10x so lange ist.
    Zum Rumprobieren und Verstehen brauchst du keinen Code der 10x so lange ist.
    Also hast du uns im ersten Beitrag angeschummelt. Oder aber dein Test-Code ist ca. 20x so lang und umständlich wie er sein müsste.
    So einfach ist das.

    Hast du da evtl. den Link oben zum kompletten Project/Source übersehen?

    Nein, es interessiert mich bloss überhaupt nicht ne Solution runterzuladen. Wieso sollte ich das tun? Ist doch nur umständlich.

    mathi schrieb:

    Auch noch ein PS.:

    hustbaer schrieb:

    Und es ist nicht nur nicht genug da, sondern gleichzeitig auch viel zu viel. Dass da in dem Programm wo du das anwenden willst mit Fenstern rumgemacht wird, interessiert ja für die Frage "wie tu ich vtable patchen" nicht.

    Zu viel, zu wenig? Du hast um den Source gebeten. Der Fenster kram ist raus, das Framework ist zu erkennen. Komplett Projekt ist verlinkt ... Was mach ich Falsch? Oder anders gefragt, womit ecke ich bei dir an?

    Ja, der Fensterkram ist raus. Fast. Dafür auch der Aufruf der Funktion. Was soll man also damit? Das was du hier gepostet hast (direkt, vergiss die verlinkte Solution!) kann nicht funktionieren. Wieso sollte sich den Code dann jmd. angucken? Du verschwendest bloss unsere Zeit. Kommentare wie "hier passiert jetzt das und das" (wo der Code dazu aber fehlt) sind uninteressant. Wer sagt denn dass der Fehler nicht evtl. genau DA zu finden ist?

    *seufz*

    Guck mal, SO sieht ein Beispiel aus. Das lässt sich 1:1 bauen, ist nicht sinnlos in 15 Files aufgeteilt. Und es funktioniert sogar.

    #define _WIN32_WINNT 0x0500
    
    #include <windows.h>
    #include <string>
    #include <iostream>
    
    // Die originalen Klassen
    
    class Base
    {
    public:
    	virtual ~Base() {} // Slot 0
    	virtual void Slot1() {}
    	virtual void Slot2() {}
    	virtual int Foo(int param1, char const* param2, std::string param3) // // Slot 3
    	{ 
    		std::cout << "Base: " << param1 << " " << param2 << " " << param3 << "\n";
    		val = 11;
    		return 1;
    	}
    
    	int val;
    };
    
    class Derived : public Base
    {
    public:
    	virtual int Foo(int param1, char const* param2, std::string param3)
    	{
    		std::cout << "Derived: " << param1 << " " << param2 << " " << param3 << "\n";
    		val = 22;
    		return 2;
    	}
    };
    
    // Die Funktion die wir reinpatchen wollen
    
    int __fastcall ThePatchedFoo(Base* that, int /*EDX*/, int param1, char const* param2, std::string param3)
    {
    	std::cout << "PATCH: " << param1 << " " << param2 << " " << param3 << "\n";
    	that->val = 99;
    	return 9;
    }
    
    // Die Hilfsfunktion zum Patchen
    
    typedef void(*SomeFunctionPtr)();
    
    template <class T>
    void OptimizationBarrier(T const& t)
    {
    	char dummy[sizeof(T) + 1];
    	dummy[0] = 0;
    	memcpy(&dummy[1], &t, sizeof(T));
    	::OutputDebugStringA(dummy);
    }
    
    template <class T, class F>
    SomeFunctionPtr PatchItBaby(T* instance, int slotIndex, F* function)
    {
     	OptimizationBarrier(instance); // Vermutlich in diesem Fall nicht nötig - funktioniert zumindest auch im Release ohne den Aufruf
    
    	SomeFunctionPtr* vTable = *reinterpret_cast<SomeFunctionPtr**>(instance);
    	SomeFunctionPtr& vTableSlot = vTable[slotIndex];
    
    	DWORD oldPageFalgs = 0;
    	VirtualProtect(&vTableSlot, sizeof(SomeFunctionPtr), PAGE_EXECUTE_READWRITE, &oldPageFalgs);
    
    	SomeFunctionPtr oldValue = vTableSlot;
    	vTableSlot = reinterpret_cast<SomeFunctionPtr>(function);
    
    	VirtualProtect(&vTableSlot, sizeof(SomeFunctionPtr), oldPageFalgs, NULL);
    
     	OptimizationBarrier(instance); // Vermutlich nicht nötig, siehe oben
    
    	return oldValue;
    }
    
    // Der Testcode
    
    Base* g_base;
    
    void Test()
    {
    	int rv = g_base->Foo(42, "p2", "the_mighty_param_3");
    	std::cout << "Foo returned: " << rv << "\n";
    	std::cout << "val = " << g_base->val << "\n";
    	std::cout << "\n";
    }
    
    int main()
    {
    	g_base = new Derived();
    	// Mal mit dem Original
    	Test();
    
    	// Patchen und probieren
    	SomeFunctionPtr original = PatchItBaby(g_base, 3, &ThePatchedFoo);
    	Test();
    
    	// Und wieder zurückpatchen und nochmal probieren
    	PatchItBaby(g_base, 3, original);
    	Test();
    }
    

    Ergebnis:

    Derived: 42 p2 the_mighty_param_3
    Foo returned: 2
    val = 22
    
    PATCH: 42 p2 the_mighty_param_3
    Foo returned: 9
    val = 99
    
    Derived: 42 p2 the_mighty_param_3
    Foo returned: 2
    val = 22
    

    In diesem Fall das erwünschte.

    Hätte ich aber eine Frage, dann wäre diese jetzt für jeden klar nachzuvollziehen.
    Es wäre weiters anzunehmen dass ich den Code nicht fürs Forum verunstaltet habe, und damit vermutlich den eigentlichen Fehler entfernt, dafür 5 neue eingefügt. Sondern dass der 1:1 so compilierbar ist und 1:1 genau das Ergebnis ausspuckt was ich gepostet habe.



  • @hustbaer

    Wundervoller Beitrag

    @mathi

    Wenn du es nicht verstehst, hilft dir bei VTables kein Beispiel was.

    Das Verständnis von VTables ergibt sich nicht aus der Anwendung oder dem Debuggen.
    Das Verständnis von VTables ergibt sich über das Verständnis von Assembler und den Abläufen in die C++ den Code umsetzt. VTable Manipulation ist eine Direkte Manipulation in den unterliegenden Verwaltungsstrukturen der Klassen.

    Googel VTable Hook und such dir was passendes für dein Verständnis raus.



  • Just Additional schrieb:

    Das Verständnis von VTables ergibt sich nicht aus der Anwendung oder dem Debuggen.

    Das ist ohne Zweifel korrekt. Allerdings können solche Beispiele das theorethische Wissen oder sagen wir mal lieber in meinem Fall, die wage Ahnung von dem, was da passiert, stützen. Ich muss ja nicht alles wissen und vollkommen verstehen 😉
    Zu dem Thema vTable Hook ect. Habe ich bereits ne große Linksammlung. Vieles davon hat sich allerdings um das einbringen von asm jmp direktiven, also soweit ich das verstanden habe, nicht um das eigentliche ersetzen einer Funktion, sondern um das "Hinspringen" zu einer anderen Funktion gedreht. Das war mir dann doch zu viel. Oder es wurde eher oberflächlich mit psydo source erklärt und dann auf bestehende libs verwiesen.

    @hustbaer:
    Ich kann mich Just Additional da nur anschließen. Wirklich elegant gelöst. Vielen lieben Dank für deine Mühe. Die generische Umsetzung der Problematik ist wirklich schön zu lesen und erschlägt so automatisch ne ganze Menge Folgefragen.

    Eine habe ich da allerdings noch: Die Funktion OptimizationBarrier macht doch in dem Beispiel nichts weiter, als den übergebenen Parameter in ein lokales array zu kopieren (mit einem offset von 1). Die sollte doch bestimmt was wichtiges(?) bewirken? Kannst du dazu nochmal was sagen?



  • mathi schrieb:

    Die Funktion OptimizationBarrier macht doch in dem Beispiel nichts weiter, als den übergebenen Parameter in ein lokales array zu kopieren (mit einem offset von 1).

    Ne, die macht mehr. Sie ruft dann nämlich OutputDebugStringA mit einem Zeiger auf dieses Array auf. (Dazu ist auch das Nullbyte am Anfang gut: so erkennt OutputDebugStringA hier nen leeren String und tut im Endeffekt nix.)
    Der Knackpunkt ist dass OutputDebugStringA ne Kernelfunktion ist. Und ich gehe mal davon aus, dass der Compiler nicht weiss was die tut.

    D.h. der Compiler sieht dass hier eine Funktion, von der total unbekannt ist was sie machen könnte, mit einem Zeiger auf ein Array gefüttert wurde, wo was vorher was reinkopiert wurde.

    D.h. der Compiler muss annehmen, dass der Wert der da reinkopiert wurde jedem denkbaren Programmteil bekannt sein könnte, und dass auch alles was über diesen Wert erreichbar ist (wenn der Wert z.B. ein Zeiger ist), von OutputDebugStringA verändert hätte werden können.

    Kurzum: Wenn du schreibst

    Foo* f = new Foo();
    f->VirtualFunction();
    

    Dann kann der Compiler eigentlich sehen dass hier wirklich ein Foo erstellt wird, und VirtualFunction direkt aufrufen, ohne den Umweg über den vTable.

    Hier dagegen:

    Foo* f = new Foo();
    OptimizationBarrier(&f);
    f->VirtualFunction();
    

    kann er das nimmer.
    Weil er nicht sicher sein kann ob OptimizationBarrier(&f) nicht vielleicht den Wert von f geändert haben könnte.

    ---

    Wobei... vermutlich wäre es besser die Adresse des übergebenen Teils zu kopieren statt den Inhalt.
    Dann könnte man das & weglassen, also nur OptimizationBarrier(f) schreiben.



  • Ok, Danke nochmals!

    Einen schönen Abend,
    mathi


Anmelden zum Antworten