Relacionado a una pregunta previa mía
He interpuesto con éxito malloc
, pero calloc
parece ser más problemático.
Con ciertos hosts, el calloc
se bloquea en un bucle infinito con una posible llamada interna dentro de dlsym
. Sin embargo, un host de prueba básico no presenta este comportamiento, pero el comando “ls” de mi sistema sí lo hace.
Aquí está mi código:
// build with: g++ -O2 -Wall -fPIC -ldl -o libnano.so -shared Main.cc #include #include bool gNanoUp = false;// global // Function types typedef void* (*MallocFn)(size_t size); typedef void* (*CallocFn)(size_t elements, size_t size); struct MemoryFunctions { MallocFn mMalloc; CallocFn mCalloc; }; MemoryFunctions orgMemFuncs; // Save original methods. void __attribute__((constructor)) __nano_init(void) { fprintf(stderr, "NANO: init()\n"); // Get address of original functions orgMemFuncs.mMalloc = (MallocFn)dlsym(RTLD_NEXT, "malloc"); orgMemFuncs.mCalloc = (CallocFn)dlsym(RTLD_NEXT, "calloc"); fprintf(stderr, "NANO: malloc() found @%p\n", orgMemFuncs.mMalloc); fprintf(stderr, "NANO: calloc() found @%p\n", orgMemFuncs.mCalloc); gNanoUp = true; } // replacement functions extern "C" { void *malloc(size_t size) { if (!gNanoUp) __nano_init(); return orgMemFuncs.mMalloc(size); } void* calloc(size_t elements, size_t size) { if (!gNanoUp) __nano_init(); return orgMemFuncs.mCalloc(elements, size); } }
Ahora, cuando hago lo siguiente, obtengo un bucle infinito seguido de una falla de seg, por ejemplo:
% setenv LD_PRELOAD "./libnano.so" % ls ... NANO: init() NANO: init() NANO: init() Segmentation fault (core dumped)
Sin embargo, si comento el intercalador de calloc
, casi parece funcionar:
% setenv LD_PRELOAD "./libnano.so" % ls NANO: init() NANO: malloc() found @0x3b36274dc0 NANO: calloc() found @0x3b362749e0 NANO: init() NANO: malloc() found @0x3b36274dc0 NANO: calloc() found @0x3b362749e0 ...
Así que algunas cosas con “ls” significa que se llama dos veces a init()
.
EDITAR Tenga en cuenta que el siguiente progtwig host funciona correctamente: init()
solo se llama una vez, y el calloc
se interpone con éxito, como se puede ver en la salida.
// build with: g++ test.cc -o test #include #include int main(int argc, char* argv[]) { void* p = malloc(123); printf("HOST p=%p\n", p); free(p); char* c = new char; printf("HOST c=%p\n", c); delete c; void* ca = calloc(10,10); printf("HOST ca=%p\n", ca); free(ca); } % setenv LD_PRELOAD "./libnano.so" % ./test NANO: init() NANO: malloc() found @0x3b36274dc0 NANO: calloc() found @0x3b362749e0 HOST p=0x601010 HOST c=0x601010 HOST ca=0x601030
Con respecto a __nano_init()
se llama dos veces: ha declarado la función como un constructor, por lo que se llama cuando se carga la biblioteca y se llama explícitamente una segunda vez cuando se llama por primera vez a las implementaciones de malloc()
y calloc()
. Elegir uno.
Con respecto a la interposición de calloc()
bloquea su aplicación: algunas de las funciones que está utilizando, como dlsym()
y fprintf()
, pueden estar intentando asignar memoria, llamando a las funciones de su interposición. Considera las consecuencias, y actúa en consecuencia.
El uso de dlsym
basados en dlsym
puede provocar lockings, ya que dlsym
vuelve a llamar al asignador de memoria. En su lugar, use ganchos malloc , como sugerí en su pregunta anterior ; estos se pueden instalar sin invocar realmente dlsym
en absoluto.
Sé que llego un poco tarde (6 años). Pero quería anular calloc()
hoy y enfrenté un problema porque dlsym()
usa internamente calloc()
. Lo resolví usando una técnica simple y pensé en compartirlo aquí:
static unsigned char buffer[8192]; void *calloc(size_t nmemb, size_t size) { if (calloc_ptr == NULL) // obtained from dlsym return buffer; init(); // uses dlsym() to find address of the real calloc() return calloc_ptr(len); } void free(void *in) { if (in == buffer) return; free_ptr(in); }
buffer
satisface la necesidad de dlsym()
hasta que se haya localizado el calloc()
real calloc()
y se calloc_ptr
inicializado el puntero de mi función calloc_ptr
.
Puede salirse con un calloc deficiente preliminar que simplemente devuelve NULL. Esto realmente funciona en Linux, YMMV.
static void* poor_calloc(size_t nmemb, size_t size) { // So dlsym uses calloc internally, which will lead to infinite recursion, since our calloc calls dlsym. // Apparently dlsym can cope with slightly wrong calloc, see for further explanation: // http://blog.bigpixel.ro/2010/09/interposing-calloc-on-linux return NULL; // This is a poor implementation of calloc! }