2010-01-20 16 views
8

Me gustaría reemplazar el global operator new() y operator delete() (junto con todas sus variantes) para hacer algunos trucos de administración de memoria. Me gustaría que todos los códigos de mi aplicación usen los operadores personalizados (incluido el código en mis propias DLL y DLL de terceros). He leído cosas en el sentido de que el vinculador elegirá la primera definición que ve al vincular (por ejemplo, si la biblioteca que contiene su personalizado operator new() está vinculado primero, "batirá" el enlace con el CRT). ¿Hay alguna manera de garantizar que esto suceda? ¿Cuáles son las reglas para esto, ya que este es realmente un símbolo definido de forma múltiple (por ejemplo, void* operator new(size_t size) tiene dos definiciones en el espacio de nombre global)?¿Es posible reemplazar el "operador new() global" en todas partes?

¿Qué pasa con los archivos DLL de terceros que pueden estar vinculados estáticamente con el CRT? Incluso si están vinculados dinámicamente con el CRT, ¿hay alguna manera de lograr que se vinculen con myoperator new()?

+6

Esto está lleno de peligros. ¿Estás seguro de que quieres hacer esto (s/N)? > –

+1

Los archivos DLL son binarios, por lo que ya se han compilado y vinculado para cuando los hay. – KingRadical

+2

Bastante justo. Solo pregunto porque me sentiría mal si tu próxima pregunta de StackOverflow es "¿cómo puedo recuperar datos en un sistema de producción muy importante?" ;) –

Respuesta

7

El estándar C++ explícitamente le permite escribir su propio operador global nuevo y eliminar (y variantes de matriz). El enlazador tiene que hacer que funcione, aunque exactamente cómo le corresponde a los implementadores (por ejemplo, cosas como los externos débiles pueden ser útiles para suministrar algo si y solo si uno no está presente).

En cuanto a las DLL, va a ser complicado: una DLL estáticamente vinculada claramente no usará su código sin mucho trabajo adicional. La vinculación estática significa que ya tiene una copia del código de la biblioteca copiada en la DLL, y cualquier código en la DLL que lo usó tiene la dirección de ese código ya codificado. Para evitar eso, tendrías que averiguar dónde está el código de nuevo en el archivo DLL y parchear de forma dinámica todo el código que lo llama para llamar al tuyo en su lugar).

Si el DLL se vincula dinámicamente a la biblioteca estándar, se vuelve solo marginalmente más fácil: la tabla de importación aún codifica el nombre de la DLL y funciona en esa DLL que proporciona lo que necesita. Eso se puede evitar (por ejemplo, con algo como el Detours library de Microsoft), pero es algo no trivial (aunque es ciertamente más fácil que cuando el DLL vincula estáticamente la biblioteca estándar).

3

EDITAR: Después de volver a leer la pregunta, me doy cuenta de que su énfasis está en los componentes de terceros. Entonces, en ese caso, la respuesta es no. Hay demasiadas variables involucradas.


(Refiriéndose a la sustitución de la "nueva" en su propio código) La respuesta corta es sí. Este es un truco común en los sistemas que hacen su propia gestión de memoria. Como habrás adivinado, es muy complicado acertar, y puede explotar fácilmente en tu cara si no tienes cuidado, pero es ciertamente plausible y lo usan muchos programas. (Recuerdo haber leído un código que hace esto en el Doom 3 SDK, por ejemplo)

En cuanto a reemplazar nuevo y eliminar en un DLL de terceros, eso no va a suceder (al menos no de forma segura). Por un lado, ¿cómo sabes que incluso usan nuevo y eliminar? Sin mencionar que pueden estar haciendo su propia variante de esta técnica y confiar en algún efecto secundario para funcionar correctamente. E incluso si lo hace funcionar ahora, ¿cómo sabe que alguna versión futura de ese componente no lo romperá? Siéntete libre de ensuciar con tu propia memoria todo lo que quieras, pero por tu cordura y la de tus usuarios, no intentes microgestionar la memoria de otros binarios.

Cuestiones relacionadas