how can i override malloc(), calloc(), free() etc under OS X?

Assuming the latest XCode and GCC, what is the proper way to override the memory allocation functions (I guess operator new/delete as well). The debugging memory allocators are too slow for a game, I just need some basic stats I can do myself with minimal impact.

I know its easy in Linux due to the hooks, and this was trivial under codewarrior ten years ago when I wrote HeapManager.

  • How to embed an executable in my project
  • How to inspect the responder chain?
  • Develop iPhone application remotely?
  • How to implement IOServiceMatchingCallBack in Swift
  • Programmatically Disable Mouse & keyboard
  • How do I play a sound in Mac OS?
  • Sadly smartheap no longer has a mac version.

    7 Solutions Collect From Internet About “how can i override malloc(), calloc(), free() etc under OS X?”

    I would use library preloading for this task, because it does not require modification of the running program. If you’re familiar with the usual Unix way to do this, it’s almost a matter of replacing LD_PRELOAD with DYLD_INSERT_LIBRARIES.

    First step is to create a library with code such as this, then build it using regular shared library linking options (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);
    }
    

    Note that if you also divert calloc() and its implementation calls malloc(), you may need additional code to check how you’re being called. C++ programs should be pretty safe because the new operator calls malloc() anyway, but be aware that no standard enforces that. I have never encountered an implementation that didn’t use malloc(), though.

    Finally, set up the running environment for your program and launch it (might require adjustments depending on how your shell handles environment variables):

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

    See the dyld manual page for more information about the dynamic linker environment variables.

    This method is pretty generic. There are limitations, however:

    • You won’t be able to divert direct system calls
    • If the application itself tricks you by using dlsym() to load malloc‘s address, the call won’t be diverted. Unless, however, you trick it back by also diverting dlsym!

    The malloc_default_zone technique mentioned at http://lists.apple.com/archives/darwin-dev/2005/Apr/msg00050.html appears to still work, see e.g. http://code.google.com/p/fileview/source/browse/trunk/fileview/fv_zone.cpp?spec=svn354&r=354 for an example use that seems to be similar to what you intend.

    After much searching (here included) and issues with 10.7 I decided to write a blog post about this topic: How to set malloc hooks in OSX Lion

    You’ll find a few good links at the end of the post with more information on this topic.

    The basic solution:

    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
    }
    

    If the basic stats you need can be collected in a simple wrapper, a quick (and kinda dirty) trick is just using some #define macro replacement.

    void* _mymalloc(size_t size)
    {
        void* ptr = malloc(size);
    
        /* do your stat work? */
    
        return ptr;
    }

    and

    #define malloc(sz_) _mymalloc(sz_)

    Note: if the macro is defined before the _mymalloc definition it will end up replacing the malloc call inside that function leaving you with infinite recursion… so ensure this isn’t the case. You might want to explicitly #undef it before that function definition and simply (re)define it afterward depending on where you end up including it to hopefully avoid this situation.

    I think if you define a malloc() and free() in your own .c file included in the project the linker will resolve that version.

    Now then, how do you intend to implement malloc?

    Check out Emery Berger’s — the author of the Hoard memory allocator’s — approach for replacing the allocator on OSX at https://github.com/emeryberger/Heap-Layers/blob/master/wrappers/macwrapper.cpp (and a few other files you can trace yourself by following the includes).

    This is complementary to Alex’s answer, but I thought this example was more to-the-point of replacing the system provided allocator.

    This is an old question, but I came across it while trying to do this myself. I got curious about this topic for a personal project I was working on, mainly to make sure that what I thought was automatically deallocated was being properly deallocated. I ended up writing a C++ implementation to allow me to track the amount of allocated heap and report it out if I so chose.

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

    As the name notes, this is OSX-specific. However, I was able to do this on Linux environments using the malloc_usable_size

    Example

    #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);
    }
    

    Building

    $ 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
    

    Hope this helps someone else out in the future!