Una alternativa para la obsoleta funcionalidad de gancho malloc de glibc


Estoy escribiendo un perfilador de memoria para C y para eso estoy interceptando llamadas a la malloc, realloc y free funciona a través de malloc_hooks. Desafortunadamente, estos están obsoletos debido a su mal comportamiento en entornos multihilo. No pude encontrar un documento que describa la solución alternativa de mejores prácticas para lograr lo mismo, ¿puede alguien iluminarme?

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 intrusivo para la base de código original para ser adecuado para su uso en una herramienta de creación de perfiles / rastreo. Tener que cambiar manualmente el código de la aplicación original es un asesino para cualquier generador de perfiles decente. De manera óptima, la solución que estoy buscando debe habilitarse o deshabilitarse simplemente enlazando a una biblioteca compartida opcional. Por ejemplo, mi configuración actual utiliza una función declarada con __attribute__ ((constructor)) para instalar los ganchos interceptores malloc.

Gracias

Author: Guy Avraham, 2013-07-23

2 answers

Después de probar algunas cosas, finalmente me las arreglé para averiguar 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 su lugar, implementé la siguiente función en una biblioteca compartida:

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

Que es llamado por la aplicación en lugar de glibc s malloc.

Ahora, para ser equivalente a la funcionalidad de __malloc_hook, un par de todavía faltan cosas.

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

Además De los parámetros originales para malloc, glibcs __malloc_hooks también proporcionar la dirección de la función de llamada, que es en realidad la dirección de retorno de donde malloc gustaría volver a. Para lograr lo mismo, podemos usar la función __builtin_return_address que está disponible en gcc. No he mirado en otros compiladores, porque estoy limitado a gcc de todos modos, pero si le sucede a saber cómo hacer tal cosa portable, por favor 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 malloc original. Alternativamente, se puede usar dlsym(RTLD_NEXT, "malloc"), pero ante la posible trampa de que esta función use calloc en su primera llamada, posiblemente dando como resultado un bucle infinito que conduce a un fallo de segmento.

Gancho malloc completo

Mi completa la función de enganche 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 se 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.

Enlaces dinámicos y estáticos

Con estas funciones, el enlace dinámico funciona fuera de la caja. Vincular el archivo. so que contiene la implementación del gancho malloc resultará de todas las llamadas a malloc desde la aplicación y también de todas las llamadas a la biblioteca que se enrutarán a través de mi gancho. La vinculación estática es problemática aunque. Todavía no he envuelto mi cabeza alrededor de él por completo, pero en el enlace estático malloc no es un símbolo débil, lo que resulta en un error de definición múltiple en el momento del enlace.

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

Aquí hay un breve ejemplo:

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

3rdparty será enlazado estáticamente, mientras que malloc_hook_library estará vinculado dinámicamente, lo que resulta en el comportamiento esperado, y las direcciones de las funciones en 3rdparty para ser traducible a través de símbolos de depuración en test. Bastante limpio, ¿eh?

Conusion

Las técnicas anteriores describen un enfoque no obsoleto, bastante equivalente a __malloc_hooks, 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 GNU en glibc

Las banderas enlazadoras -Wl,-Bstatic y -Wl,-Bdynamic son específicas de los binutils de GNU.

En otras palabras, esta solución es completamente no portable y se tendrían que agregar soluciones alternativas si la biblioteca hooks fuera portada a un sistema operativo que no sea GNU.

 36
Author: Andreas Grapentin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-22 13:32:55

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

 2
Author: vinayak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-23 08:05:37