Функция интерпозиции работает только для malloc, а не бесплатно

Я столкнулся с небольшой проблемой при мониторинге malloc и free из-за использования интерпозиции функций.

При выполнении интерпозиции функции только для malloc она работает так, как ожидалось. Однако при попытке вставить free он также зацикливается; мне кажется, что бесплатно вызывается рекурсивно, но я просто не знаю, почему.

Это код функций malloc и free. (mod_malloc_free.c)

#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>

void* malloc(size_t size) {

   static void* (*real_malloc)(size_t) = NULL;

   printf("%s\n", "inside shared malloc");

   if(!real_malloc)
        real_malloc = dlsym(RTLD_NEXT, "malloc");

   void * p = real_malloc(size);

   printf("malloc(%d) = %p\n",size, p );

   printf("%s\n", "returning from shared malloc");

   return p;

   }

void free(void* ap ) {

    static void (*real_free)(void*) = NULL;

  printf("inside shared free...\n");

  if(!real_free)
       real_free = dlsym(RTLD_NEXT, "free");

   printf("free = %p\n", ap);

   real_free(ap);

}

Основная просто состоит из:

#include <stdio.h>
#include <malloc.h>

int main(void) {

    void * p = malloc(123);

    printf("p = %p\n",p );

    free(p);

    return 0;

}

Скомпилировано как:

gcc -shared -ldl -fPIC mod_malloc_free.c -o libcustom.so

gcc -o smallMain -Стена smallMain.c

LD_PRELOAD=./libcustom.so ./smallMain

С наилучшими пожеланиями

Найфикен


person me_L_coding    schedule 21.02.2013    source источник
comment
Вы можете взглянуть на stackoverflow .com/questions/6083337/ stackoverflow.com/questions/7811656/ stackoverflow.com/questions/10913186/ и т. д.   -  person Yann Droneaud    schedule 21.02.2013
comment
Бьюсь об заклад, что dlsym звонит бесплатно... ;)   -  person Mats Petersson    schedule 21.02.2013
comment
Вы должны принять во внимание тот факт, что printf() может позвонить malloc() и free(). Это, скорее всего, происходит (следовательно, рекурсивный free())   -  person Hasturkun    schedule 21.02.2013
comment
Обратите внимание, что стандартного заголовка с именем malloc.h не существует. Функции malloc и free находятся в stdlib.h.   -  person Lundin    schedule 21.02.2013


Ответы (3)


glibc предоставляет реальный символ (не слабый) с префиксом __. Поэтому попробуйте найти символы __malloc и __free.

И просто для предотвращения рекурсии не используйте printf() или любые другие функции, которым может потребоваться выделение памяти внутри вашей оболочки.

person Yann Droneaud    schedule 21.02.2013
comment
Я добавил префикс, но это не сработало, так как их не удалось найти. Однако без префикса это работало для malloc. - person me_L_coding; 21.02.2013
comment
объявите версию с префиксом как extern и используйте их напрямую. Это был способ, которым я использовал, чтобы преодолеть ограничения getgroups в старые времена. - person Yann Droneaud; 21.02.2013

Скорее всего, printf звонит free. Конечно, это подразумевает, что он также выполняет выделение памяти, поэтому возникает вопрос, почему вы не видите рекурсивных вызовов в malloc. Скорее всего, printf вызывает альтернативу, такую ​​как calloc или realloc.

Чтобы вставить только свой собственный код, используйте макросы для замены вызовов или свяжите свой код отдельно и используйте функции компоновщика, чтобы удалить ваши malloc и free перед связыванием с внешними библиотеками (например, переключатель -unexported_symbol для Apple-версии ld).

Чтобы вставить во весь код, удалите printf из ваших подпрограмм. Вместо этого вызывайте более простые подпрограммы, такие как fputs. В качестве альтернативы используйте статический флаг для подавления рекурсии:

void free(void *ap)
{
    static void (*RealFree)(void *) = 0;
    If (!RealFree)
        RealFree = dlsym(RTLD_NEXT, "free");

    static int InsideCall = 0;
    if (!InsideCall)
    {
        InsideCall = 1;
        … Do stuff…
        InsideCall = 0;
    }
}

(Если у вас есть несколько потоков или обработчиков исключений, которые выполняют выделение памяти, необходимо предпринять дополнительные шаги.)

person Eric Postpischil    schedule 21.02.2013
comment
Спасибо за ответ, я принял предложенный вами код и заставил его работать; также printf был заменен на fputs. - person me_L_coding; 21.02.2013
comment
Но проблема все еще остается, я не могу получить какие-либо данные из приложения, такие как адреса выделенных блоков. Причина их желания заключается в том, что я хочу записать использование malloc/free, т.е. я хочу знать все размеры выделения и различные бесплатные вызовы (в том же порядке, в котором они были вызваны). Я намерен позже воспроизвести это распределение с помощью моей пользовательской функции malloc и free. - person me_L_coding; 21.02.2013
comment
@me_L_coding: это звучит как отдельный вопрос. Вы не можете получить данные, потому что сейчас не используете printf или по какой-то другой причине? Существуют различные альтернативы: Используйте printf со статическим кодом флага. Используйте fputs, но сделайте свое собственное форматирование, чтобы преобразовать адреса в удобочитаемые значения. Используйте fputs для записи адресов в двоичном формате. Создайте структуры данных для записи значений во время вставленных подпрограмм и при выходе из программы используйте другую подпрограмму для чтения этих структур и записи данных. - person Eric Postpischil; 21.02.2013
comment
Спасибо за повтор! Поясню, что я имел ввиду в предыдущем комментарии. Я действительно заставил приложение работать, т.е. Я перестал использовать функцию, зависящую от malloc, такую ​​как printf(3). Только теперь моя проблема в том, что я не могу вывести какие-либо важные данные из приложения, поскольку эти функции используют malloc. Скажем, я хотел запустить приложение, такое как Emacs, вместе с моими хуками; каким-то образом я хочу иметь возможность извлекать размеры распределения, которые использует emacs, а также различные вызовы free(3). (конечно, сохраняя порядок этих вызовов). По сути, это моя настоящая большая проблема. - person me_L_coding; 22.02.2013

Я бы посоветовал вам использовать макрос для замены malloc/free вашими собственными функциями вместо использования указателей на функции.

Что-то вроде этого должно сделать это:

 #ifdef REPLACE_MALLOC
 #define malloc(x) my_mallc(x)
 #define free(x)   my_free(x)
 #endif

Не забудьте сделать:

 #undef malloc
 #undef free

до фактической реализации.

Обратите внимание, однако, что технически это не «правильно» — вы не должны использовать макросы для вещей, которые являются частью стандартной библиотеки, поэтому, пожалуйста, не приходите сюда стонать, если она перестанет работать — в частности, Microsoft уже делает что-то подобное заменить malloc на отладочную версию в отладочных сборках.

person Mats Petersson    schedule 21.02.2013