Переопределение «malloc» с использованием механизма LD_PRELOAD

Я пытаюсь написать простую общую библиотеку, которая будет записывать вызовы malloc в stderr (что-то вроде «mtrace», если хотите).

Однако это не работает. Вот что я делаю:

/* mtrace.c */ #include  #include  static void* (*real_malloc)(size_t); void *malloc(size_t size) { void *p = NULL; fprintf(stderr, "malloc(%d) = ", size); p = real_malloc(size); fprintf(stderr, "%p\n", p); return p; } static void __mtrace_init(void) __attribute__((constructor)); static void __mtrace_init(void) { void *handle = NULL; handle = dlopen("libc.so.6", RTLD_LAZY); if (NULL == handle) { fprintf(stderr, "Error in `dlopen`: %s\n", dlerror()); return; } real_malloc = dlsym(handle, "malloc"); if (NULL == real_malloc) { fprintf(stderr, "Error in `dlsym`: %s\n", dlerror()); return; } } 

Я скомпилирую это с помощью:

 gcc -shared -fPIC -o mtrace.so mtrace.c 

И затем, когда я пытаюсь выполнить ls :

 $ LD_PRELOAD=./mtrace.so ls malloc(352) = Segmentation fault 

Теперь я подозреваю, что dlopen нуждается в malloc, и, поскольку я переопределяю его в общей библиотеке, он использует эту версию с еще неназначенным real_malloc .

Вопрос в том, как … я могу заставить его работать?

PS Извините за скудность в тегах, я не смог найти соответствующие tags, и у меня все еще недостаточно репутации для создания новых.

Я всегда так делаю:

 #define _GNU_SOURCE #include  #include  static void* (*real_malloc)(size_t)=NULL; static void mtrace_init(void) { real_malloc = dlsym(RTLD_NEXT, "malloc"); if (NULL == real_malloc) { fprintf(stderr, "Error in `dlsym`: %s\n", dlerror()); } } void *malloc(size_t size) { if(real_malloc==NULL) { mtrace_init(); } void *p = NULL; fprintf(stderr, "malloc(%d) = ", size); p = real_malloc(size); fprintf(stderr, "%p\n", p); return p; } 

Не используйте конструкторы, просто инициализируйте при первом вызове malloc . Используйте RTLD_NEXT чтобы избежать dlopen . Вы также можете попробовать крючки malloc . Имейте в виду, что все это расширения GNU и, вероятно, не работают в других местах.

Если вы действительно хотите использовать LD_PRELOAD с malloc и обнаружили, что код в принятом ответе по-прежнему сохраняется, у меня есть решение, которое, похоже, работает.

Сегфакт был вызван dlsym вызовом calloc для 32 байтов, что вызвало рекурсию в конец стека.

Мое решение состояло в том, чтобы создать суперпростой статический распределитель, который заботится о распределениях, прежде чем dlsym вернет указатель функции malloc.

 #define _GNU_SOURCE #include  #include  #include  #include  char tmpbuff[1024]; unsigned long tmppos = 0; unsigned long tmpallocs = 0; void *memset(void*,int,size_t); void *memmove(void *to, const void *from, size_t size); /*========================================================= * interception points */ static void * (*myfn_calloc)(size_t nmemb, size_t size); static void * (*myfn_malloc)(size_t size); static void (*myfn_free)(void *ptr); static void * (*myfn_realloc)(void *ptr, size_t size); static void * (*myfn_memalign)(size_t blocksize, size_t bytes); static void init() { myfn_malloc = dlsym(RTLD_NEXT, "malloc"); myfn_free = dlsym(RTLD_NEXT, "free"); myfn_calloc = dlsym(RTLD_NEXT, "calloc"); myfn_realloc = dlsym(RTLD_NEXT, "realloc"); myfn_memalign = dlsym(RTLD_NEXT, "memalign"); if (!myfn_malloc || !myfn_free || !myfn_calloc || !myfn_realloc || !myfn_memalign) { fprintf(stderr, "Error in `dlsym`: %s\n", dlerror()); exit(1); } } void *malloc(size_t size) { static int initializing = 0; if (myfn_malloc == NULL) { if (!initializing) { initializing = 1; init(); initializing = 0; fprintf(stdout, "jcheck: allocated %lu bytes of temp memory in %lu chunks during initialization\n", tmppos, tmpallocs); } else { if (tmppos + size < sizeof(tmpbuff)) { void *retptr = tmpbuff + tmppos; tmppos += size; ++tmpallocs; return retptr; } else { fprintf(stdout, "jcheck: too much memory requested during initialisation - increase tmpbuff size\n"); exit(1); } } } void *ptr = myfn_malloc(size); return ptr; } void free(void *ptr) { // something wrong if we call free before one of the allocators! // if (myfn_malloc == NULL) // init(); if (ptr >= (void*) tmpbuff && ptr <= (void*)(tmpbuff + tmppos)) fprintf(stdout, "freeing temp memory\n"); else myfn_free(ptr); } void *realloc(void *ptr, size_t size) { if (myfn_malloc == NULL) { void *nptr = malloc(size); if (nptr && ptr) { memmove(nptr, ptr, size); free(ptr); } return nptr; } void *nptr = myfn_realloc(ptr, size); return nptr; } void *calloc(size_t nmemb, size_t size) { if (myfn_malloc == NULL) { void *ptr = malloc(nmemb*size); if (ptr) memset(ptr, 0, nmemb*size); return ptr; } void *ptr = myfn_calloc(nmemb, size); return ptr; } void *memalign(size_t blocksize, size_t bytes) { void *ptr = myfn_memalign(blocksize, bytes); return ptr; } 

Надеюсь, это поможет кому-то.

Если вы используете glibc, вы должны использовать встроенный механизм привязки malloc – пример на этой странице содержит пример того, как искать исходный malloc. Это особенно важно, если вы добавляете дополнительную информацию отслеживания в распределения, чтобы гарантировать, что функции библиотеки, которые возвращают буферы malloc’d, соответствуют вашей free() реализации.

Interesting Posts

Печать «привет мир» каждые X секунд

mongo – не удалось подключиться к серверу 127.0.0.1:27017

Должен ли я налагать максимальную длину на пароли?

Как я могу дать eclipse больше памяти, чем 512M?

Ffmpeg приостанавливает видео каждые 10 секунд в течение 3 секунд

получение программной плотности экрана в андроиде?

Unity EventManager с делегатом вместо UnityEvent

Назначить одну структуру другому в C

Как сделать обнаружение сети с помощью широковещательной передачи UDP

Создайте мультизагрузочный USB-накопитель с Ubuntu и Windows 7 с использованием образов ISO

Windows 7 говорит, что 8,6-гигабайтный файл не поместится в 14,7 ГБ пространства?

Мои браузеры не будут использовать мое полное разрешение экрана, а также использовать разные разрешения между ними

Java: инициализировать несколько переменных для цикла init?

JQuery: найдите текст и замените

Восстановить окно открытия экрана?

Давайте будем гением компьютера.