как я могу переопределить malloc (), calloc (), free () и т.д. под OS X? - PullRequest
11 голосов
/ 30 мая 2009

Предполагая последние XCode и GCC, как правильно переопределить функции выделения памяти (я думаю, оператор new / delete также). Распределители памяти отладки слишком медленные для игры, мне просто нужны некоторые базовые характеристики, которые я могу сделать сам с минимальным воздействием.

Я знаю, что это легко в Linux из-за хуков, и это было тривиально для Codewarrior десять лет назад, когда я писал HeapManager.

К сожалению, у smartheap больше нет версии для Mac.

Ответы [ 7 ]

9 голосов
/ 31 мая 2009

Я бы использовал предварительную загрузку библиотеки для этой задачи, потому что она не требует модификации работающей программы. Если вы знакомы с обычным Unix-способом сделать это, это почти вопрос замены LD_PRELOAD на DYLD_INSERT_LIBRARIES.

Первый шаг - создать библиотеку с таким кодом, а затем собрать ее, используя обычные параметры связывания с общей библиотекой (gcc -dynamiclib):

void *malloc(size_t size)
{
    void * (*real_malloc)(size_t);
    real_malloc = dlsym(RTLD_NEXT, "malloc");

    fprintf(stderr, "allocating %lu bytes\n", (unsigned long)size);
    /* Do your stuff here */

    return real_malloc(size);
}

Обратите внимание, что если вы также перенаправили calloc() и вызовы его реализации malloc(), вам может потребоваться дополнительный код, чтобы проверить, как вас вызывают. Программы на C ++ должны быть достаточно безопасными, потому что оператор new в любом случае вызывает malloc(), но имейте в виду, что ни один стандарт не обеспечивает этого. Я никогда не сталкивался с реализацией, которая не использовала бы malloc().

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

export DYLD_INSERT_LIBRARIES=./yourlibrary.dylib
export DYLD_FORCE_FLAT_NAMESPACE=1
yourprogram --yourargs

См. на странице справочника dyld для получения дополнительной информации о переменных среды динамического компоновщика.

Этот метод довольно общий. Однако существуют ограничения:

  • Вы не сможете перенаправлять прямые системные вызовы.
  • Если само приложение обманывает вас, используя dlsym() для загрузки адреса malloc, вызов не будет переадресован. Если, однако, вы не обманываете это, также отклоняя dlsym!
3 голосов
/ 30 мая 2009

Техника malloc_default_zone, упомянутая в http://lists.apple.com/archives/darwin-dev/2005/Apr/msg00050.html, по-прежнему работает, см., Например, http://code.google.com/p/fileview/source/browse/trunk/fileview/fv_zone.cpp?spec=svn354&r=354 для примера использования, которое похоже на то, что вы намереваетесь.

1 голос
/ 30 июня 2016

Это старый вопрос, но я столкнулся с ним, пытаясь сделать это сам. Мне стало любопытно на эту тему для личного проекта, над которым я работал, главным образом для того, чтобы убедиться, что то, что я считал автоматически освобожденным, было правильно удалено. Я закончил тем, что написал реализацию C ++, чтобы позволить мне отслеживать количество выделенной кучи и сообщать об этом, если я того пожелал.

https://gist.github.com/monitorjbl/3dc6d62cf5514892d5ab22a59ff34861

Как следует из названия, это зависит от OSX. Тем не менее, я смог сделать это в среде Linux, используя malloc_usable_size

Пример

#define MALLOC_DEBUG_OUTPUT
#include "malloc_override_osx.hpp"

int main(){
   int* ip = (int*)malloc(sizeof(int));
   double* dp = (double*)malloc(sizeof(double));

   free(ip);
   free(dp);
}

Строительство

$ clang++ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk \
          -pipe -stdlib=libc++ -std=gnu++11 -g -o test test.cpp
$ ./test
0x7fa28a403230 -> malloc(16) -> 16
0x7fa28a403240 -> malloc(16) -> 32
0x7fa28a403230 -> free(16) -> 16
0x7fa28a403240 -> free(16) -> 0

Надеюсь, это поможет кому-то еще в будущем!

1 голос
/ 29 июля 2011

После долгих поисков (сюда входит) и проблем с 10.7 я решил написать сообщение в блоге на эту тему: Как установить перехватчики malloc в OSX Lion

В конце поста вы найдете несколько хороших ссылок с дополнительной информацией по этой теме.

Базовое решение:

malloc_zone_t *dz=malloc_default_zone();
if(dz->version>=8)
{
    vm_protect(mach_task_self(), (uintptr_t)malloc_zones, protect_size, 0, VM_PROT_READ | VM_PROT_WRITE);//remove the write protection
}
original_free=dz->free;
dz->free=&my_free; //this line is throwing a bad ptr exception without calling vm_protect first
if(dz->version==8)
{
    vm_protect(mach_task_self(), (uintptr_t)malloc_zones, protect_size, 0, VM_PROT_READ);//put the write protection back
}
0 голосов
/ 22 июля 2014

Ознакомьтесь с подходом Эмери Бергера - автора распределителя памяти Хоарда - для замены распределителя в OSX на https://github.com/emeryberger/Heap-Layers/blob/master/wrappers/macwrapper.cpp (и нескольких других файлах, которые вы можете отследить самостоятельно, следуя включениям).

Это дополняет ответ Алекса, но я подумал, что этот пример больше подходит для замены выделенного системой распределителя.

0 голосов
/ 30 мая 2009

Я думаю, что если вы определите malloc () и free () в своем собственном файле .c, включенном в проект, компоновщик разрешит эту версию.

Теперь, как вы собираетесь реализовать malloc?

0 голосов
/ 30 мая 2009

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

void* _mymalloc(size_t size)
{
    void* ptr = malloc(size);

    /* do your stat work? */

    return ptr;
}

и

#define malloc(sz_) _mymalloc(sz_)

Примечание : если макрос определен за до определения _mymalloc, он в конечном итоге заменит вызов malloc внутри этой функции, оставляя вас с бесконечной рекурсией ... так что убедитесь, что это не так т дело. Возможно, вы захотите явно #undef его до определения этой функции и просто (пере) определить его позже, в зависимости от того, где вы в конечном итоге включите его, чтобы избежать этой ситуации.

...