2009-08-27 11 views
7

Entiendo que las asignaciones de memoria realizadas en un dll y luego en otro libre pueden causar todo tipo de problemas, especialmente con respecto al CRT. Este tipo de problemas son especialmente problemáticos cuando se trata de exportar contenedores STL. Hemos experimentado este tipo de problemas antes (cuando se escribe a medida Adobe plugins que enlazaban con nuestras bibliotecas) y hemos trabajado alrededor de estas cuestiones mediante la definición de nuestra propia asignador que utilizamos en todos nuestros envases, por ejemplo:Asignación y desasignación de memoria a través de los límites de dll

typedef std::vector < SessionFields, 
     OurAllocator <SessionFields> > 
     VectorSessionFields; 

typedef std::set < SessionFields, 
     std::less <SessionFields>, 
     OurAllocator <SessionFields> > 
     SetSessionFields; 

Esto ha funcionado bien al pasar tipos a/desde nuestro código, sin embargo, hemos encontrado un problema porque ahora tenemos que llamar a una función en el SDK de Adobe que devuelve un vector poblado que causa un bloqueo cuando sale del alcance .

Obviamente, es un problema con la memoria asignada en el SDK de Adobe que pertenece a un montón diferente cuando finalmente está libre en mi código. Así que estoy pensando que tal vez podría hacer algo inteligente como reemplazar o exportar el asignador utilizado en su SDK para poder usarlo para limpiar los contenedores devueltos de sus funciones.

También estoy buscando en la escritura de un contenedor o algún tipo de capa de procesador mediante el cual los contenedores STL se proceda a seguridad entre el código y el SDK (aunque esto suena muy desordenado).

Alternativamente, también estoy buscando usando GetProcessHeaps para identificar el montón usado dentro del SDK, y trato de liberarlo contra este montón, en lugar del montón predeterminado.

¿Alguien tiene algún consejo sobre cómo podemos resolver este problema?

Respuesta

0

Puede intentar ver si hay alguna regla formal de C++ para lo que sucede cuando se lanza una excepción en una DLL y se atrapa en otra y luego se sale del alcance, parece muy similar. Para excepciones, creo que debe proporcionar un constructor de copia con una firma especial, aunque ahora no estoy seguro de qué es exactamente.

6

Irónicamente, las bibliotecas de origen de Adobe tienen una clase adobe::capture_allocator que se escribió específicamente con este tipo de seguridad DLL en mente. La forma en que funciona es capturar el new y el delete locales en este punto en el que se crea una instancia, y llevarlos a ambos durante la vida útil del objeto. (Consulte adobe::new_delete_t para obtener detalles sobre cómo se hace esto, especialmente la implementación here). Las desasignaciones tienen lugar con la rutina delete capturada, lo que garantiza que no importa dónde esté eliminando con el delete adecuado.

se puede ver capture_allocator utilizan en todo el version_1 tipos en los Adobe Source Libraries, como adobe::any_regular_t y adobe::copy_on_write. capture_allocator debe ser compatible con todos los tipos de contenedores STL también.

Actualización: capture_allocator no cumple con las normas porque conserva el estado. Esto no debería ser un gran obstáculo para su usabilidad, pero sí significa que su uso no está garantizado para funcionar con contenedores que cumplan con los estándares.

+0

Esta es una técnica muy común, también la he visto en C donde una biblioteca requiere que sus usuarios proporcionen una devolución de llamada de asignación/desasignación a través de algún tipo de punto de biblioteca init(). – Justin

2

Por el momento estamos trabajando en un dll que expone la funcionalidad de C++ a través de una interfaz C (por el bien de que C# sea capaz de usar dicho dll).

por ejemplo: la DLL tiene un myStruct_s struct la interfaz expone los siguientes funciones:

interface.h

#ifndef INTERFACE_TYPES_H 
# error Please include interace_types.h 
#endif 
    myStruct_s * CreateTheStruct() { return new myStruct_s(); } 
    void DestroyTheStruct(myStruct_s * the_struct) { delete the_struct; } 
    void DoSomethingToTheStruct(myStruct_s * the_struct); 

interface_types.h

#define INTERFACE_TYPES_H 
struct myStruct_s; // fwd declaration 
#endif 

interfaz .cpp

#if defined(__CPPPLUS) || defined(__cplusplus) || defined (__CPLUSPLUS) 
#include<TheRealFileContainingTheRealMyStruct_s.h> 
// handle the .h's functions here 
#endif 

comeOutsideCppFile.cpp

#include "interface_types.h" 
#include "interface.h" 

void main() 
{ 
    myStuct_s * x = CreateTheStruct; 
    DoSomethingToTheStruct(x); 
    DestroyTheStruct(x); 
} 

Lo anterior es un esbozo de cómo funciona nuestras cosas, básicamente: Cualquiera que sea la DLL expone necesita ser: Creado, manipulados, destruidos DLL- lado

¡Este código no es 100% exacto!

Además, tenga en cuenta que si está utilizando un dll puro de C++, probablemente necesite el mismo compilador con la misma configuración que el utilizado para construir el dll.

+1

@Maciek: interface.h debe contener funciones NO EN LINEA. Al hacer las funciones en línea, se compilarán en la unidad de compilación de comeOutsideCppFile.cpp, lo que arruina el concepto. – shojtsy

Cuestiones relacionadas