LD_PRELOAD работает только для malloc, не бесплатно

Я пытаюсь вставить malloc/free/calloc/realloc и т. д. с некоторыми интерпозерами через LD_PRELOAD. В моем небольшом тесте кажется, что вставляется только malloc, хотя обнаруживается free (см. вывод).

Я ожидал, что вывод будет содержать строку «NANO: free(x)», но эта строка отсутствует.

Данный

// compile with: gcc test.cc
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]) {

    void* p = malloc(123);
    printf("HOST p=%p\n", p);
    free(p);
}

И

// compile with:  g++ -O2 -Wall -fPIC -ldl -o libnano.so -shared main.cc
#include <stdio.h>
#include <dlfcn.h>

typedef void *(*MallocFunc)(size_t size);
typedef void (*FreeFunc)(void*);

// Original functions
static MallocFunc real_malloc = NULL;
static FreeFunc real_free = NULL;

static void __nano_init(void) {
    // Override original functions
    real_malloc = (MallocFunc)dlsym(RTLD_NEXT, "malloc");
    if (NULL == real_malloc) {
        fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
    } else {
        fprintf(stderr, "NANO: malloc() replaced @%p\n", real_malloc);
    }

    real_free = (FreeFunc)dlsym(RTLD_NEXT, "free");
    if (NULL == real_free) {
       fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
    } else {
        fprintf(stderr, "NANO: free() replaced @%p\n", real_free);
    }
}

// replacement functions
void *malloc(size_t size) {
    if(real_malloc==NULL) __nano_init();

    void *p = NULL;
    fprintf(stderr, "NANO: malloc(%lu) = ", size);
    p = real_malloc(size);
    fprintf(stderr, "%p\n", p);

    return p;
}

void free(void* ptr) {
    if(real_free==NULL) __nano_init();

    fprintf(stderr, "NANO: free(%p)\n", ptr);
    real_free(ptr);

    return;
}

Фактический результат:

% ./a.out
NANO: malloc() replaced @0x3b36274dc0
NANO: free() replaced @0x3b36272870
NANO: malloc(123) = 0x601010
HOST p=0x601010

person Justicle    schedule 18.10.2011    source источник


Ответы (1)


Вы компилируете C++; это означает, что (по умолчанию) имена функций искажаются, чтобы соответствовать C++ ABI. К сожалению, имена функций, которые вы пытаетесь перехватить, не искажены, поэтому в итоге вы перехватите неправильную (несуществующую) функцию.

Исправление состоит в том, чтобы либо а) определить свои оболочки в блоке extern "C" { }, либо а) убедиться, что вы включили заголовок для функции - как в #include <cstdlib>. Это вытянет объявления для malloc и free с оболочкой extern "C", говоря компилятору, чтобы он не искажал имена.

Причина, по которой malloc работает, вероятно, заключается в том, что <stdio.h> или <dlfcn.h> извлекает объявление для malloc но не free. Таким образом, malloc не искажается, а free искажается.

Также обратите внимание: если вы используете glibc, вы должны использовать хуки malloc для перехвата функций выделения памяти. glibc делает довольно странные вещи с версионированием символов, которые в противном случае могут помешать вашим хукам. Пример того, как его использовать, находится в связанной документации — не забудьте extern "C"s, если вы используете C++!

person bdonlan    schedule 18.10.2011
comment
Коверкание имени Аргх. Точно. Получается, что все примеры, которые я использовал, где C/gcc. Я должен был понять, когда перешел на g++. Спасибо за подсказку - сейчас я бы предпочел оценить прямую технику LD_PRELOAD. Я не уверен в каких-либо преимуществах крючков malloc. - person Justicle; 18.10.2011
comment
@bdonian, если вы в игре, у меня есть дополнительный вопрос: stackoverflow.com/questions/7910666/ - person Justicle; 27.10.2011