c gcc malloc deprecated glibc

glibc version



Una alternativa para la funcionalidad__malloc_hook en desuso de glibc (2)

Puede usar LD_PRELOAD & dlsym Consulte "Consejos para malloc y gratis" en http://www.slideshare.net/tetsu.koba/presentations

Estoy escribiendo un perfilador de memoria para C y estoy interceptando llamadas a las funciones malloc, realloc y free a través de malloc_hooks. Desafortunadamente, estos están en desuso debido a su comportamiento deficiente en entornos multiproceso. No pude encontrar un documento que describiera la solución alternativa de mejores prácticas para lograr lo mismo, ¿alguien me puede aclarar?

He leído que un simple #define malloc(s) malloc_hook(s) haría el truco, pero eso no funciona con la configuración del sistema que tengo en mente, porque es demasiado intrusiva para la base del código original como para ser adecuado para usar en una herramienta de perfilado / rastreo. Tener que cambiar manualmente el código de la aplicación original es un asesino para cualquier perfilador decente. De manera óptima, la solución que estoy buscando debe habilitarse o deshabilitarse simplemente mediante el enlace a una biblioteca compartida opcional. Por ejemplo, mi configuración actual utiliza una función declarada con __attribute__ ((constructor)) para instalar los enlaces de interceptación de malloc.

Gracias


Después de probar algunas cosas, finalmente logré descubrir cómo hacer esto.

En primer lugar, en glibc , malloc se define como un símbolo débil, lo que significa que puede ser sobrescrito por la aplicación o una biblioteca compartida. Por lo tanto, LD_PRELOAD no es necesariamente necesario. En cambio, implementé la siguiente función en una biblioteca compartida:

void* malloc (size_t size) { [ ... ] }

Que se llama por la aplicación en lugar de glibc s malloc .

Ahora, para ser equivalente a la funcionalidad __malloc_hook , aún faltan algunas cosas.

1.) la dirección de la persona que llama

Además de los parámetros originales de malloc , glibc s __malloc_hook s también proporcionan la dirección de la función de llamada, que en realidad es la dirección de retorno de donde regresaría malloc . Para lograr lo mismo, podemos usar la función __builtin_return_address que está disponible en gcc. No he investigado otros compiladores, porque de todos modos estoy limitado a gcc, pero si sabe cómo hacerlo de manera portátil, envíeme un comentario :)

Nuestra función malloc ahora se ve así:

void* malloc (size_t size) { void *caller = __builtin_return_address(0); [ ... ] }

2.) accediendo a glibc s malloc desde dentro de su gancho

Como estoy limitado a glibc en mi aplicación, elegí usar __libc_malloc para acceder a la implementación original de malloc. Alternativamente, se dlsym(RTLD_NEXT, "malloc") , pero ante la posible trampa de que esta función use calloc en su primera llamada, posiblemente resulte en un bucle infinito que conduzca a una segfault.

completar el gancho malloc

Mi función de enganche completa ahora se ve así:

extern void *__libc_malloc(size_t size); int malloc_hook_active = 0; void* malloc (size_t size) { void *caller = __builtin_return_address(0); if (malloc_hook_active) return my_malloc_hook(size, caller); return __libc_malloc(size); }

donde my_malloc_hook ve así:

void* my_malloc_hook (size_t size, void *caller) { void *result; // deactivate hooks for logging malloc_hook_active = 0; result = malloc(size); // do logging [ ... ] // reactivate hooks malloc_hook_active = 1; return result; }

Por supuesto, los ganchos para calloc , realloc y free funcionan de manera similar.

enlace dinámico y estático

Con estas funciones, la vinculación dinámica funciona de la caja. Vincular el archivo .so que contiene la implementación de malloc hook resultará en todas las llamadas a malloc desde la aplicación y también todas las llamadas a la biblioteca que se enrutarán a través de mi gancho. La vinculación estática es problemática sin embargo. Todavía no me he acostumbrado por completo, pero en el enlace estático malloc no es un símbolo débil, lo que da como resultado un error de definición múltiple en el tiempo del enlace.

Si necesita enlaces estáticos por cualquier razón, por ejemplo, traducir direcciones de funciones en bibliotecas de terceros a líneas de código mediante símbolos de depuración, puede vincular estas bibliotecas de terceros estáticamente mientras sigue enlazando dinámicamente los ganchos malloc, evitando el problema de definición múltiple. Todavía no he encontrado una solución mejor para esto, si conoce uno, siéntase libre de dejarme un comentario.

Aquí hay un pequeño ejemplo:

gcc -o test test.c -lmalloc_hook_library -Wl,-Bstatic -l3rdparty -Wl,-Bdynamic

3rdparty se vinculará estáticamente, mientras que malloc_hook_library se vinculará dinámicamente, dando como resultado el comportamiento esperado, y las direcciones de funciones en 3rdparty para ser traducibles a través de símbolos de depuración en test . Bastante limpio, ¿eh?

Conlusion

las técnicas anteriores describen un enfoque no __malloc_hook , bastante equivalente, para __malloc_hook s, pero con un par de limitaciones medias:

__builtin_caller_address solo funciona con gcc

__libc_malloc solo funciona con glibc

dlsym(RTLD_NEXT, [...]) es una extensión de GNU en glibc

los indicadores del enlazador -Wl,-Bstatic y -Wl,-Bdynamic son específicos de los binutils de GNU.

En otras palabras, esta solución es totalmente no portátil y las soluciones alternativas tendrían que agregarse si la biblioteca de ganchos fuera a ser portada a un sistema operativo que no sea GNU.