Создать функцию-обертку для malloc и бесплатно в C - PullRequest
37 голосов
/ 04 ноября 2008

Я пытаюсь создать функции-оболочки для free и malloc в C, чтобы уведомить меня об утечках памяти. Кто-нибудь знает, как объявить эти функции, чтобы при вызове malloc() и free() он вызывал мои пользовательские функции, а не стандартные функции lib?

Ответы [ 9 ]

71 голосов
/ 04 ноября 2008

У вас есть несколько вариантов:

  1. Специальное решение GLIBC (в основном Linux). Если ваша среда компиляции glibc с gcc, предпочтительным способом является использование malloc hooks . Он не только позволяет указывать пользовательские malloc и free, но также идентифицирует вызывающего по адресу возврата в стеке.

  2. Специфичное для POSIX решение. Определите malloc и free как оболочки для исходных процедур выделения в вашем исполняемом файле, которые будут "переопределять" версию из libc. Внутри оболочки вы можете вызвать оригинальную реализацию malloc, которую вы можете найти, используя dlsym с ручкой RTLD_NEXT. Ваше приложение или библиотека, которые определяют функции-оболочки, должны быть связаны с -ldl.

    #define _GNU_SOURCE
    #include <dlfcn.h>
    #include <stdio.h>
    
    void* malloc(size_t sz)
    {
        void *(*libc_malloc)(size_t) = dlsym(RTLD_NEXT, "malloc");
        printf("malloc\n");
        return libc_malloc(sz);
    }
    
    void free(void *p)
    {
        void (*libc_free)(void*) = dlsym(RTLD_NEXT, "free");
        printf("free\n");
        libc_free(p);
    }
    
    int main()
    {
        free(malloc(10));
        return 0;
    }
    
  3. Специфично для Linux. Вы можете неинвазивно переопределять функции из динамических библиотек, указав их в переменной среды LD_PRELOAD.

    LD_PRELOAD=mymalloc.so ./exe
    
  4. для Mac OSX.

    То же, что и в Linux, за исключением того, что вы будете использовать DYLD_INSERT_LIBRARIES переменную окружения.

16 голосов
/ 03 января 2011

Вы можете сделать обертку и функцию «перезаписать» с LD_PRELOAD - аналогично примеру, показанному ранее.

LD_PRELOAD=/path.../lib_fake_malloc.so ./app

Но я рекомендую сделать это "немного" умнее, я имею в виду вызов dlsym один раз .

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

void* malloc(size_t size)
{
    static void* (*real_malloc)(size_t) = NULL;
    if (!real_malloc)
        real_malloc = dlsym(RTLD_NEXT, "malloc");

    void *p = real_malloc(size);
    fprintf(stderr, "malloc(%d) = %p\n", size, p);
    return p;
}

пример, который я нашел здесь: http://www.jayconrod.com/cgi/view_post.py?23 сообщение от Jay Conrod.

Но то, что я нашел действительно классным на этой странице, это то, что: GNU linker предоставляет полезную опцию, - wrap Когда я проверяю "man ld", есть следующий пример:

void *
__wrap_malloc (size_t c)
{
    printf ("malloc called with %zu\n", c);
    return __real_malloc (c);
}

Я согласен с ними, что это "тривиальный пример" :). Даже дслым не нужен.

Позвольте мне привести еще одну часть моей страницы "man ld":

--wrap=symbol
       Use a wrapper function for symbol.
       Any undefined reference to symbol will be resolved to "__wrap_symbol".
       Any undefined reference to "__real_symbol" will be resolved to symbol.

Надеюсь, описание завершено и показывает, как использовать эти вещи.

5 голосов
/ 06 ноября 2008

Вот набор функций-оболочек, которые я использовал годами (и до сих пор использую, когда погружаюсь в C), чтобы обнаруживать несвободную память, многократно свободную память, ссылки на свободную память, переполнения / недостаточности буфера и освобождение памяти, которая не была выделена.

FTP: //ftp.digitalmars.com/ctools.zip

Они существуют уже 25 лет и зарекомендовали себя.

Вы можете использовать макрос-препроцессор для переопределения malloc и свободно использовать пакеты из пакета mem, но я рекомендую против этого, потому что он не будет перенаправлять вызовы библиотек в malloc, как это делает strdup.

5 голосов
/ 04 ноября 2008

В С метод, который я использовал, был похож на:

#define malloc(x) _my_malloc(x, __FILE__, __LINE__)
#define free(x) _my_free(x)

Это позволило мне без особого труда определить строку и файл, где была выделена память. Он должен быть кроссплатформенным, но возникнут проблемы, если макрос уже определен (что должно быть в случае, если вы используете другой детектор утечки памяти).

Если вы хотите реализовать то же самое в C ++, процедура будет немного более сложной , но использует тот же прием.

4 голосов
/ 20 ноября 2015

Извините за повторное открытие поста 7 лет.

В моем случае мне нужно было обернуть memalign / align_malloc под malloc. Попробовав другие решения, я реализовал одно из перечисленных ниже. Вроде нормально работает.

mymalloc.c .

/* 
 * Link-time interposition of malloc and free using the static
 * linker's (ld) "--wrap symbol" flag.
 * 
 * Compile the executable using "-Wl,--wrap,malloc -Wl,--wrap,free".
 * This tells the linker to resolve references to malloc as
 * __wrap_malloc, free as __wrap_free, __real_malloc as malloc, and
 * __real_free as free.
 */
#include <stdio.h>

void *__real_malloc(size_t size);
void __real_free(void *ptr);


/* 
 * __wrap_malloc - malloc wrapper function 
 */
void *__wrap_malloc(size_t size)
{
    void *ptr = __real_malloc(size);
    printf("malloc(%d) = %p\n", size, ptr);
    return ptr;
}

/* 
 * __wrap_free - free wrapper function 
 */
void __wrap_free(void *ptr)
{
    __real_free(ptr);
    printf("free(%p)\n", ptr);
}
4 голосов
/ 04 ноября 2008

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

2 голосов
/ 04 ноября 2008

Если вы определяете свои собственные функции для malloc () и free () и явно связываете их с вашими приложениями, ваши функции следует использовать вместо тех, которые в библиотеке.

Однако ваша функция с именем 'malloc' не может затем вызвать библиотечную функцию malloc, потому что в 'c' нет понятия отдельных пространств имен. Другими словами, вам нужно реализовать внутреннюю часть malloc и освободить себя.

Другой подход заключается в написании функций my_malloc () и my_free (), которые вызывают стандартные библиотечные. Это будет означать, что любой код, вызывающий malloc, должен быть изменен для вызова ваших функций my_xxx.

0 голосов
/ 04 ноября 2008

Если вы говорите только о памяти, которая находится под вашим контролем, то есть о том, что вы используете malloc и свободны самостоятельно, вы можете взглянуть на rmdebug . Вероятно, это то, что вы собираетесь написать, так что вы можете сэкономить время. У него очень либеральная лицензия, если это важно для вас.

Лично я использую его в проекте, чтобы искать утечки памяти. Приятно то, что он намного быстрее, чем valgrind, однако он не настолько мощный, поэтому вы не получаете полный стек вызовов.

0 голосов
/ 04 ноября 2008

Если вы используете Linux, вы можете использовать malloc_hook () (с GNU glibc). Эта функция позволяет malloc вызывать вашу функцию до вызова фактического malloc. Страница man содержит пример того, как ее использовать.

...