C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Walker
Beiträge: 15
Registriert: 28.07.2017, 08:58
Alter Benutzername: Walker

C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Walker » 05.09.2019, 08:38

Hintergrund ist ein Designfehler in Basisklassen vor über 15 Jahren. Minimalistisches Beispiel:

Code: Alles auswählen

class Base
{
  vector<*Base> Childs;
  virtual void Build();
  void BuildChilds() {   for(...) Child->Build();...}
}

class Derived : public Base
{
     ... void Build();
}
class DerivedX : public Derived
{
     void Build()
     {
          Base::Build(); // Dinge bauen die alle brauchen
          
         // ... baue Dinge speziell für diese Klasse, erzeuge ggf. Childs!!
         
         BuildChilds(); // Wenn Childs.. lass diese auch was bauen..
     }
}

von "Derived" gibt es 1000de von abgeleiteten Klassen (bei über zig verschiedenen Firmen die mit der gleichen Basis arbeiten).

Der Aufruf von Build so einer Klasse kann von überall passieren. Es ist nicht immer nur die Hierarchie die in den Basisklassen das steuern, aber da wollen wir wieder hin.

Jetzt wollen wir die Struktur und Dinge der Build-Funktion anders verarbeiten/steuern um einiges zu optimieren und auf Änderungen effektiver zu reagieren.

Jetzt die Frage: Kann man irgendwie einen Event/Meldung/Ping bekommen wenn eine Derived::Build() Funktion angetriggert wird um diese dann ggf. umzuleiten oder den Aufruf zu steuern ?

Ausser den Source aller Ableger (ist vorhanden, könnte automatisiert werden) zu bearbeiten habe ich so keine Idee.

Ich weiß das man irgendwie die vTable lesen kann. Aber einen Hook einsetzen der das dann umdeligiert ?
C++ MVS 2012



Danke.

Benutzeravatar
Schrompf
Moderator
Beiträge: 3905
Registriert: 26.02.2009, 00:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Schrompf » 05.09.2019, 13:51

Haua. Das könnte kompliziert werden. Du könntest die Aufrufe der Ableitungen in eine andere Funktion auslagern, um die entsprechend zu überladen und darin vielleicht mit typeinfo() was zu zaubern. Das, was Du willst, klingt für mich wie "Instrumentieren", und das wird knifflig. In der Basisklasse den VTable umzuschreiben wär nicht nur ein fieser Hack, sondern auch nutzlos, weil C++ die Compiler verpflichtet, die VTables bei jeder Ableitungsstufe auf genau den aktuellen Typ ohne Ableitungen einzurichten.
Häuptling von Dreamworlds. Baut an was Neuem. Hilft nebenbei nur höchst selten an der Open Asset Import Library mit.

Spiele Programmierer
Establishment
Beiträge: 357
Registriert: 23.01.2013, 16:55

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Spiele Programmierer » 05.09.2019, 21:04

Schrompf hat recht, es reicht nicht die Vtable der Basisklasse zu verändern sondern du musst alle Vtables der abgeleiteten Klassen ändern.
Das Überschreiben von Funktionen funktioniert ja gerade dadurch, dass in der abgeleiteten Klasse die Basisklassen-Vtable der Instanz mit der Vtable der abgeleiteten Klasse ersetzt wird, die dann auf die abgeleiteten Funktionen verweisen kann.

Der C++ Standard bietet hier also nichts und alles was mir einfällt ist höchst platformspezifisch und auch noch ungeheuerlich hässlich und sehr langsam. Rein theoretisch könnte man natürlich so Dinge Richtung machen wie zum Programmstart nach vtables scannen und alle die, die von Base ableiten, entsprechend modifizieren. Oder ausgehend vom Base-Konstruktor versuchen, Zugriff auf die Vtable der abgeleitete Klasse zu erhalten. Beispielsweise in dem man einen Speicherhaltepunkt auf den Zeiger zur Vtable setzt und die Windows-Exception auffängt und entsprechend behandelt.

Das würde ich an deiner Stelle aber lieber lassen.
Ein automatisiertes Tool scheint mir in diesem Fall noch die beste Lösung. Einen Hack umzusetzen wäre bestimmt auch mehr Aufwand als das Tool. Wäre es für dich eigentlich nicht auch denkbar, einfach nach void Build() zu suchst und in (beispielweise) void BuildLegacy() umzubennen? Dann kannst du eine neue Build-Methode in de Basisklasse einführen die das macht was du willst.

Benutzeravatar
xq
Establishment
Beiträge: 1340
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von xq » 05.09.2019, 22:18

Eventuell kann dir hier Microsoft Detours helfen:
https://github.com/microsoft/Detours

Damit kannst du irgendwie Funktionen umrouten
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Wer checkt diese Shaderprogrammierung denn?
JCL: Kein Mensch zwingt Sie jedoch, mit Shadern oder ueberhaupt mit Gamestudio zu arbeiten. Es gibt schliesslich auch andere schoene Hobbies, wie zum Beispiel das Sammeln von Bierdeckeln – JCL quotes

Walker
Beiträge: 15
Registriert: 28.07.2017, 08:58
Alter Benutzername: Walker

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Walker » 06.09.2019, 06:52

Danke. Ich glaube Detours routet nur API Funktionen um so wie ich das sehe. Quasi Man in the middle.

Alexander Kornrumpf
Moderator
Beiträge: 1682
Registriert: 25.02.2009, 14:37

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Alexander Kornrumpf » 06.09.2019, 07:37

Jetzt die Frage: Kann man irgendwie einen Event/Meldung/Ping bekommen wenn eine Derived::Build() Funktion angetriggert wird um diese dann ggf. umzuleiten oder den Aufruf zu steuern ?
Ich kenne mich mit C++ nicht sehr gut aus, aber Event/Meldung/Ping an eine zentrale Stelle bekommst du doch gratis, weil die Ableitung Base::Build() aufruft. Ich hatte mich noch gefragt welchen dynamischen Typ this in Base::Build() hat, falls du RTTI machen musst, aber ich nehme doch mal sehr an es ist DerivedX.

Beliebigen Code kannst du von Base::Build() aus auch ausführen.

Du kannst sogar den Rest der Ausführung von DerivedX::Build() von Base::Build() aus verhindern indem du eine Exception wirfst.

Theoretisch bist du damit zu 80% da wenn du die Möglichkeit hättest, die Exception am anderen Ende zu fangen.

Ob das ein leichtereres Problem ist als das ursprüngliche, oder ob ich das Problem einfach nicht verstanden habe weiß ich leider nicht.

Ist auch alles sehr unschön aber sicherlich nicht unschöner, als die vtable zu hacken.

Unabhängig davon schreit das natürlich danach auf stackoverflow gefragt zu werden und nicht hier. Falls du das schon gemacht hast, wäre ein Link nett.

Walker
Beiträge: 15
Registriert: 28.07.2017, 08:58
Alter Benutzername: Walker

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Walker » 06.09.2019, 07:59

nein, war noch nicht auf Stackoverflow.
Ja , ich bekomme Base::Build mit. Da sind aber die Dinge für mich Anonym die vor und nach dem Aufruf von Base::Build() gelaufen sind. Im Prinzip will ich genau diese Dinge splitten und in zwei Methodenaufrufe mit Rückgabewert aufteilen (jeweils vor und nach Base::Build). Der Rückgabewert soll dann steuern ob der zweite Methodenaufruf noch sein muss. Aber Base::Build ist auch nur eine Basismethode.. das kann ja auch wieder indirekt über eine weitere vorgelagerte Klasse zwischen Base und Derived aufgerufen werden. Vererbung halt. Seinerzeit nicht weit genug gedacht.

Alexander Kornrumpf
Moderator
Beiträge: 1682
Registriert: 25.02.2009, 14:37

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Alexander Kornrumpf » 06.09.2019, 08:06

I see. In dem Beispiel sah es halt so aus als wäre Base::Build() (immer) der erste Aufruf in Derived:.Build():

class DerivedX : public Derived
{
void Build()
{
Base::Build(); // Dinge bauen die alle brauchen

// ... baue Dinge speziell für diese Klasse, erzeuge ggf. Childs!!

BuildChilds(); // Wenn Childs.. lass diese auch was bauen..
}
}

Walker
Beiträge: 15
Registriert: 28.07.2017, 08:58
Alter Benutzername: Walker

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Walker » 06.09.2019, 08:21

Sorry. .. nein. Base::Build() ist nicht zwangsläufig der erste Aufruf. Oft kommen da noch Dinge die für den Aufruf von Base::Build() benötigt werden. Positionsanpassungen oder so.

Walker
Beiträge: 15
Registriert: 28.07.2017, 08:58
Alter Benutzername: Walker

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Walker » 06.09.2019, 09:37

Ich denke es wird wohl das Beste sein, die Umbenennungsaktion (wie Spiele Programmierer schrieb) anzudenken...

Benutzeravatar
Chromanoid
Moderator
Beiträge: 3847
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Chromanoid » 06.09.2019, 09:43

edit: ich war zu langsam :), ja genau! Hier trotzdem mein Original-Post:

Wenn es nur um Logging ginge, würde ich einen Stacktrace empfehlen. Darüber könntest Du den Caller von Base::Build() rauskriegen.

Kann man in C++ / C++-IDEs nicht anständig Refactoring machen? Ich würde das machen, was Spiele Programmierer vorgeschlagen hat. Also Build in BuildLegacy umbenennen. In Base wieder eine Build-Methode hinzufügen und von da aus BuildLegacy aufrufen. Von der neuen Build-Methode aus müsste es ja dann auch möglich sein, über die VTable rauszukriegen, ob die BuildLegacy-Methode in der aktuellen Instanz überschrieben wurde (falls man in dem Fall irgendwas spezielles machen will).

Walker
Beiträge: 15
Registriert: 28.07.2017, 08:58
Alter Benutzername: Walker

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Walker » 06.09.2019, 09:57

Ja man Refactoring in gewissen Grenzen machen. Aber der Sourcecode umfasst eine 3 stellige Anzahl von Projekten und mehrere Millionen Codezeilen. Das muss man automatisieren.

Benutzeravatar
Chromanoid
Moderator
Beiträge: 3847
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Chromanoid » 06.09.2019, 10:01

Vielleicht hilft Dir das hier weiter: https://github.com/cquery-project/cquery (VSCode Extension: https://marketplace.visualstudio.com/it ... ect.cquery)

Hab gerade gesehen, es gäbe wohl noch zwei Alternativen, siehe https://langserver.org/ Edit: ah, das hier ist die bessere Quelle: https://microsoft.github.io/language-se ... s/servers/

Keine Ahnung, ob die Dinger mit eurer Codebase funktionieren. Aber im Grunde sollte das einiges an Arbeit ersparen, wenn es geht.

Walker
Beiträge: 15
Registriert: 28.07.2017, 08:58
Alter Benutzername: Walker

Re: C++ Event bekommen wenn virtuelle Funktion angetriggert wird

Beitrag von Walker » 12.09.2019, 08:18

Ich denke wir werden uns da sorgfältig geprüfte Werkzeuge selber bauen. Das ganze muss auch gut koordiniert werden. Ich werde berichten wie es dann gelaufen ist. Wird aber sicherlich dauern.

Antworten