Falsches Vtable-Layout für die Klasse von DLL exportiert: Bitte um Klarstellung bezüglich Kopf- und VTable Bau

StackOverflow https://stackoverflow.com/questions/3453402

Frage

Obwohl das Problem bei der Hand ist gelöst , hat es mich ein wenig verwirrt darüber, welche Daten verwendet wird, die vtables für eine Klasse zu konstruieren, und wo das Layout für die V-Tabelle gespeichert ist. Wenn jemand Klärung zur Verfügung stellen kann oder mich auf einigen Informationen hinweisen, die meine Neugier befriedigen könnte, würde ich es sehr zu schätzen.

Hintergrund

  1. Zwei getrennte VC6.0 Projekte:. Ein für eine exe-Datei, ein für eine DLL
  2. Anwendung enthält LIB, DLL und H-Dateien von DLL-Projekt veröffentlicht.
  3. Wenn eine neue Version bereit, die LIB, DLL und H-Dateien sind Kopiert in das exe-Projekt aus dem DLL-Projekt.
  4. Ich habe dieses Schema vererbt.

Problem:

Ich habe vor kurzem eine Änderungen in der DLL und kopiert die LIB gemacht und .dll aber vergessen haben, die Header-Dateien zu kopieren. Es gab einige Hierarchie verändert und, als Folge, die V-Tabelle für eine bestimmte Klasse (nennen wir es InternalClass) geändert hatte.

Die exe funktioniert nicht direkt invoke alle Verfahren auf InternalClass . Stattdessen ist es eine Instanz einer anderen Klasse erzeugt (nennen wir es InterfaceClass), das einen Zeiger auf ein Objekt und ruft InternalClass verschiedenen Methoden gegen diese Zeiger einkapselt.

Zur Laufzeit Anrufe von innerhalb InterfaceClass Methoden InternalClass Methoden tatsächlich wurden Aufrufen der falschen Methoden (d InterfaceClass würde aufrufen InternalClass::A und InternalClass::B liefe tatsächlich). Mit Blick auf die asm , es stellt sich heraus, dass die Korrektur oder thunk (Es tut mir leid, wenn dies der falsche Jargon ist!) War die korrekte Verwendung von Offset in die V-Tabelle. Jedoch , die VTable selbst enthielt die Liste von Zeigern Sie aus dem erwarten alt Header-Dateien.

Die tatsächliche Frage:

erkannte ich meinen Fehler, kopiert die Header-Dateien über, neu kompiliert und alles war gut. Jedoch , ich bin links mit einer quälenden Frage:

Wenn das Layout für die vtables bestimmt und welche Informationen verwendet wird, um die V-Tabelle für diese Klassen zur Laufzeit zu konstruieren? Das heißt, es scheint mir, dass die richtigen VTable zusammengebaut worden sein, wenn der DLL kompiliert wurde, so dass die Offsets, etc. könnten für die Anrufe von InterfaceClass zu InternalClass verwendet werden. Warum also war eine veraltete VTable zur Laufzeit? Ist das Layout auch separat bestimmt, wenn die exe kompiliert wird unter Verwendung der Header hat?

Ich bin nicht sicher, ob dies alles andere als klar ist. Lassen Sie mich wissen, ob das, was ich frage ist zu verworren. Dank!

War es hilfreich?

Lösung

Hmm, schwere Details der Implementierung eines 12-jährigen Compiler. Wenn Sie __declspec (dllexport) für eine Klasse verwenden, exportiert der Linker die Mitglieder der Klasse. Nicht der VTable. Das wird in dem Client der Klasse rekonstruiert, wenn die Compiler die Klassendeklaration in der Header-Datei analysiert. Die Linker füllt in diesem lokalen VTable mit den exportierten Mitgliedern Adressen.

Wäre es besser funktionieren, wenn die Compiler einfach die V-Tabelle aus der DLL exportieren? Vielleicht, aber solche Implementierungsdetails Export ist furchtbar spröde. Die Angst vor sich selbst in eine Ecke zu malen, dass Sie nicht wegen der Rückwärtskompatibilität erhalten aus kann, ist ein starker Motivator, ich mir vorstellen.

Andere Tipps

Die Art und Weise Ihre beschreiben die Interaktion dieser beiden Klassen nicht völlig auf einer sehr wichtiges Detail zu klären: Ist Ihr so ??genannte InternalClass aus der DLL exportiert werden oder nicht? Oder die Frage eine andere Art und Weise zu stellen: Ist der Code in diesen kopiert Header-Dateien verwenden Zeiger auf InternalClass oder alle Wissen dieser Klasse versteckt ausschließlich innerhalb der DLL

Wenn diese Klasse in Frage tatsächlich vollständig innerhalb der dll versteckt ist, dann bin ich nicht sicher, wie dieses Problem passieren könnte. Aber von dem, was Sie beschreiben, klingt es wirklich, als ob InternalClass von der dll ausgesetzt wird.

Wenn diese Header, die vom Konzept her ähnlich enthalten über Code kopiert werden, um diese:

class InterfaceClass
{
    InternalClass* Internal;

    void DoSomething()
    {
        Internal->DoSomething();
    }
};

Dann muss der InternalClass ausgesetzt werden, da sonst das Projekt exe fehlschlagen würde den Header kompilieren. (So ??ist es nicht wirklich internes nachdem alle.)

Und wenn das der Fall ist, dann leicht erklärt es Ihr Problem. Die exe wird gegen eine andere Erklärung von InternalClass gebaut als die DLL mit gebaut wurde. Das bedeutet jede kompiliert ihre eigene Version der virtuellen Tabelle, und diese Versionen unterschiedlich sind.

Dann zur Laufzeit wird der exe-Code ein Objekt erstellt aus der dll, geben und somit mit seinen V-Tabelle Zeigern, der auf die Version der DLL des VTable. Der exe-Code versucht dann an der Arbeit durch diesen VTable-Zeiger, als ob es auf die exe-Version der V-Tabelle hingewiesen. Und es ist offensichtlich, dass Probleme verursacht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top