la disposición vtable para la clase incorrecta exportada por la DLL: solicitud de aclaración con respecto a los encabezados y la construcción vtable

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

Pregunta

A pesar de que el problema en cuestión es resuelto , que me tiene un poco confundido en cuanto a qué datos se utiliza para construir los vtables para una clase y donde el diseño de la viable se almacena. Si alguien puede aclarar o que me señale hacia alguna información que pueda saciar mi curiosidad, me sería de gran aprecio.

Fondo

  1. dos proyectos separados: VC6.0. Uno para un exe, uno para un archivo DLL
  2. Aplicación contiene .lib, .dll y los archivos .h de DLL lanzamientos de proyectos.
  3. Cuando una nueva versión está listo, el .lib, .dll y los archivos .h son copiados en el proyecto exe del proyecto DLL.
  4. Me han heredado este esquema.

Problema:

Hace poco hizo un cambio en la DLL y se copia sobre el .lib y .DLL, pero olvidó de copiar los archivos de cabecera . Ha habido algunos cambios en la jerarquía y, como resultado, la viable para una clase particular (lo llaman InternalClass) había cambiado.

¿El exe no directamente invoca ninguna métodos en InternalClass . En lugar de ello, se crea una instancia de una clase diferente (llamada él InterfaceClass) que encapsula un puntero a un objeto InternalClass e invoca varios métodos contra ese puntero.

En tiempo de ejecución, las llamadas realizadas desde dentro de los métodos InterfaceClass a métodos InternalClass eran en realidad invocando los métodos erróneos (es decir InterfaceClass podría invocar InternalClass::A y InternalClass::B habría hecho correr). En cuanto a la asm , resulta que la corrección o golpe seco (lo siento si esto es la jerga mal!) Era correcta utilizando el el desplazamiento en la viable. No obstante , la viable en sí contenía la lista de punteros que cabe esperar de la de edad los archivos de cabecera.

Pregunta Actual:

Me di cuenta de mi error, copiar los archivos de cabecera más, vuelve a compilar y todo estaba bien. No obstante , me quedo con una pregunta acuciante:

Cuando está la disposición de los vtables determinado y qué información se utiliza para construir la viable para estas clases en tiempo de ejecución? Es decir, me parece que el adecuada vtable debe haber sido montado cuando se compiló el DLL para que los desplazamientos, etc., pueden utilizarse por las llamadas entre InterfaceClass a InternalClass. ¿Por qué, entonces, era un vtable obsoleto utilizado en tiempo de ejecución? Es la disposición también determina por separado cuando el exe se compila utilizando las cabeceras que tiene?

No estoy seguro si esto es del todo claro. Déjame saber si lo que estoy pidiendo es demasiado enrevesado. Gracias!

¿Fue útil?

Solución

Hmm, los detalles de implementación de alta resistencia de una vieja compilador de 12 años. Cuando se utiliza __declspec (dllexport) en una clase, el enlazador exporta los miembros de la clase. No es la viable. Eso se reconstruyó en el cliente de la clase cuando el compilador analiza la declaración de clase en el archivo de cabecera. Los rellenos de engarce en que vtable local con las direcciones de los miembros exportados.

¿funcionaría mejor si el compilador simplemente exporta la viable desde el archivo DLL? Tal vez, pero la exportación de este tipo de detalles de implementación es muy frágil. El miedo a la pintura a sí mismo en una esquina que no se puede salir de la causa de la compatibilidad hacia atrás es un fuerte motivador, me imagino.

Otros consejos

La forma en que describen la interacción de estas dos clases no está totalmente claro en un detalle muy importante: ¿Su llamada InternalClass se exporta desde la DLL o no? O, para decirlo a la pregunta de una manera diferente:? ¿El código en los archivos de cabecera copiados utilizar punteros a InternalClass o es todos conocimiento de esa clase oculta únicamente dentro de la DLL

Si esa clase en cuestión en realidad es completamente oculto dentro de la DLL, entonces no estoy seguro de cómo este problema podría suceder. Pero de lo que describes, lo que realmente suena como si InternalClass está siendo expuesto por el DLL.

Si los encabezados que son copiadas sobre contienen código similar en concepto a esto:

class InterfaceClass
{
    InternalClass* Internal;

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

A continuación, el InternalClass debe ser expuesto, de lo contrario el proyecto del exe fallaría para compilar la cabecera. (Así que no es realmente interna después de todo.)

Y si ese es el caso, entonces se explica fácilmente su problema. El exe se está construyendo una declaración en contra de diferentes InternalClass que el DLL fue construido con. Esto significa que cada compila su propia versión de la tabla virtual, y esas versiones son diferentes.

A continuación, en tiempo de ejecución, el código exe se entregó un objeto creado desde dentro de la DLL, y por lo tanto con su vtable puntero que apunta a la versión de la DLL de la viable. El código exe luego trata de trabajo a través de ese puntero vtable como si se señaló a la versión del exe de la viable. Y, obviamente, que causa problemas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top