3

I'm debugging my program now and I get segmentation fault when erasing an element from a map. I added malloc hook to my programs which looks as follow: (UPDATED)

#pragma once

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

static void *(*old_memalign_hook)(size_t, size_t, const void *);
static void *(*old_realloc_hook)(void *, size_t, const void *);
static void *(*old_malloc_hook)(size_t, const void *);
static void (*old_free_hook)(void *, const void *);

static void *new_memalign_hook(size_t alignment, size_t size, const void *caller);
static void *new_realloc_hook(void *ptr, size_t size, const void *caller);
static void *new_malloc_hook(size_t size, const void *caller);
static void new_free_hook(void *ptr, const void *caller);
static std::map<void*, const void*> mallocMap;

static void *new_memalign_hook(size_t alignment, size_t size, const void *caller)
{
    void *mem;

    __memalign_hook = old_memalign_hook;
    __realloc_hook = old_realloc_hook;
    __malloc_hook = old_malloc_hook;
    __free_hook = old_free_hook;
    mem = memalign(alignment, size);
//    fprintf(stderr, "%p: memalign(%zu, %zu) = %p\n", caller, alignment, size, mem);
    mallocMap[mem] = caller;
//    fprintf(stderr, "mallocSet size: %zu\n", mallocMap.size());
    __memalign_hook = new_memalign_hook;
    __realloc_hook = new_realloc_hook;
    __malloc_hook = new_malloc_hook;
    __free_hook = new_free_hook;

    return mem;
}

static void *new_realloc_hook(void *ptr, size_t size, const void *caller)
{
    void *mem;

    __memalign_hook = old_memalign_hook;
    __realloc_hook = old_realloc_hook;
    __malloc_hook = old_malloc_hook;
    __free_hook = old_free_hook;
    mem = realloc(ptr, size);
//    fprintf(stderr, "%p: realloc(%p, %zu) = %p\n", caller, ptr, size, mem);
    __memalign_hook = new_memalign_hook;
    __realloc_hook = new_realloc_hook;
    __malloc_hook = new_malloc_hook;
    __free_hook = new_free_hook;

    return mem;
}

static void *new_malloc_hook(size_t size, const void *caller)
{
    void *mem;

    __memalign_hook = old_memalign_hook;
    __realloc_hook = old_realloc_hook;
    __malloc_hook = old_malloc_hook;
    __free_hook = old_free_hook;
    mem = malloc(size);
//    fprintf(stderr, "%p: malloc(%zu) = %p\n", caller, size, mem);
    mallocMap[mem] = caller;
//    fprintf(stderr, "mallocSet size: %zu\n", mallocMap.size());
    __memalign_hook = new_memalign_hook;
    __realloc_hook = new_realloc_hook;
    __malloc_hook = new_malloc_hook;
    __free_hook = new_free_hook;

    return mem;
}

static void new_free_hook(void *ptr, const void *caller)
{
    __memalign_hook = old_memalign_hook;
    __realloc_hook = old_realloc_hook;
    __malloc_hook = old_malloc_hook;
    __free_hook = old_free_hook;
    free(ptr);
    if (ptr != 0)
    {
//        fprintf(stderr, "%p: free(%p)\n", caller, ptr);
        std::map<void*, const void*>::iterator it;
        if((it = mallocMap.find(ptr)) != mallocMap.end())
        {
            mallocMap.erase(it);
        }
//        fprintf(stderr, "mallocSet size: %zu\n", mallocMap.size());
        if(mallocMap.size() == 89)
        {
            for(auto it2 = mallocMap.begin(); it2 != mallocMap.end(); it2++)
            {
//                fprintf(stderr, "mallocSet: %p %p\n", (*it2).first, (*it2).second);
            }
        }
    }
    __memalign_hook = new_memalign_hook;
    __realloc_hook = new_realloc_hook;
    __malloc_hook = new_malloc_hook;
    __free_hook = new_free_hook;
}

static void init_my_hooks(void)
{
    mallocMap = std::map<void*, const void*>();
    old_memalign_hook = __memalign_hook;
    old_realloc_hook = __realloc_hook;
    old_malloc_hook = __malloc_hook;
    old_free_hook = __free_hook;
    __memalign_hook = new_memalign_hook;
    __realloc_hook = new_realloc_hook;
    __malloc_hook = new_malloc_hook;
    __free_hook = new_free_hook;
//    fprintf(stderr, "mallocSet size: %zu\n", mallocMap.size());
}

it giving me SIGSEGV on the erase, in the new_free_hook().

in gdb i have the following prints which seems to be fine (or are they?):

(gdb) p mallocMap[ptr]
$2 = (std::map<void*, void const*, std::less<void*>, std::allocator<std::pair<void* const, void const*> > >::mapped_type &) @0x2e3c6a8: 0x0

(gdb) p it
$1 = {first = , second = <operator new(unsigned long)+29>}

(gdb) p mallocMap
$3 = std::map with 101 elements = {[0x2e39970] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e39a00] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e39ad0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e39b50] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e39c10] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e39c90] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e39d20] = 0x7ffff35392fd <operator new(unsigned long)+29>, [0x2e39d80] = 0x37f1035fe4 <__new_exitfn+276>, 
  [0x2e3a1e0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3a2b0] = 0x7ffff35392fd <operator new(unsigned long)+29>, [0x2e3a640] = 0x37f1035fe4 <__new_exitfn+276>, 
  [0x2e3ab50] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3abd0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3aca0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3ad20] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3adf0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3ae50] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3aee0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3af40] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3af70] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b000] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b050] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b0e0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b160] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b270] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b300] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b3a0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b430] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b490] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b4c0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b500] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3b590] = 0x7ffff35392fd <operator new(unsigned long)+29>, [0x2e3b5f0] = 0x37f1035fe4 <__new_exitfn+276>, 
  [0x2e3ba50] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3bab0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3bc40] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3bc60] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3bc80] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3bca0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3bd00] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3bd20] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3bd90] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3bdb0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3be10] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3be70] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3bed0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3bf50] = 0x7ffff35392fd <operator new(unsigned long)+29>, [0x2e3bfc0] = 0x0, 
  [0x2e3c120] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3c180] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3c1e0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3c240] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3c6c0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3c780] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3c7e0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3c840] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3c960] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
---Type <return> to continue, or q <return> to quit---
  [0x2e3c9f0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3ca10] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3ca70] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3cb90] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3cc00] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3cc20] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3cc40] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3cc60] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3ccc0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3cd50] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3cd70] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3cdd0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3ce30] = 0x7ffff35392fd <operator new(unsigned long)+29>, [0x2e3d140] = 0x37f1035fe4 <__new_exitfn+276>, 
  [0x2e3d5a0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3d610] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3d6e0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3d7a0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3d820] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3d8f0] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3da70] = 0x7ffff35392fd <operator new(unsigned long)+29>, 
  [0x2e3db00] = 0x7ffff35392fd <operator new(unsigned long)+29>, [0x2e3db60] = 0x37f1035fe4 <__new_exitfn+276>, 
  [0x2fc5a60] = 0x37f1035fe4 <__new_exitfn+276>, [0x300abc0] = 0x37f1035fe4 <__new_exitfn+276>, 
  [0x3014290] = 0x37f1035fe4 <__new_exitfn+276>, [0x3014750] = 0x37f1035fe4 <__new_exitfn+276>, 
  [0x3014bb0] = 0x37f1081182 <strdup+34>, [0x3014c10] = 0x37f102a409 <_nl_load_locale_from_archive+601>, 
  [0x3014cd0] = 0x37f1029e27 <_nl_intern_locale_data+119>, [0x3015020] = 0x37f1029e27 <_nl_intern_locale_data+119>, 
  [0x30150e0] = 0x37f1029e27 <_nl_intern_locale_data+119>, [0x30154e0] = 0x37f1029e27 <_nl_intern_locale_data+119>, 
  [0x3015600] = 0x37f1029e27 <_nl_intern_locale_data+119>, [0x3015800] = 0x37f1029e27 <_nl_intern_locale_data+119>, 
  [0x30158b0] = 0x37f1029e27 <_nl_intern_locale_data+119>, [0x3015950] = 0x37f1029e27 <_nl_intern_locale_data+119>, 
  [0x3015a10] = 0x37f1029e27 <_nl_intern_locale_data+119>, [0x3015b00] = 0x37f1029e27 <_nl_intern_locale_data+119>, 
  [0x3015bb0] = 0x37f1029e27 <_nl_intern_locale_data+119>, [0x3015c50] = 0x37f1029e27 <_nl_intern_locale_data+119>, 
  [0x3015d60] = 0x37f1081182 <strdup+34>, [0x3015dc0] = 0x37f1028dcd <new_composite_name+493>...}

BackTrace of the segmentation fault:

#0  std::_Rb_tree_rebalance_for_erase (__z=0x2fc5ff0, __header=...)
    at ../../../../../libstdc++-v3/src/c++98/tree.cc:370
#1  0x00007fffef1f65d4 in std::_Rb_tree<void*, std::pair<void* const, void const*>, std::_Select1st<std::pair<void* const, void const*> >, std::less<void*>, std::allocator<std::pair<void* const, void const*> > >::_M_erase_aux (
    this=0x7ffff34d9800 <mallocMap>, __position=...)
    at /usr/local/prerequisites/package-install/gcc-4.8.2/include/c++/4.8.2/bits/stl_tree.h:1745
#2  0x00007fffef1f5a1d in std::_Rb_tree<void*, std::pair<void* const, void const*>, std::_Select1st<std::pair<void* const, void const*> >, std::less<void*>, std::allocator<std::pair<void* const, void const*> > >::erase[abi:cxx11](std::_Rb_tree_iterator<std::pair<void* const, void const*> >) (this=0x7ffff34d9800 <mallocMap>, __position=...)
    at /usr/local/prerequisites/package-install/gcc-4.8.2/include/c++/4.8.2/bits/stl_tree.h:820
#3  0x00007fffef1f53ac in std::map<void*, void const*, std::less<void*>, std::allocator<std::pair<void* const, void const*> > >::erase[abi:cxx11](std::_Rb_tree_iterator<std::pair<void* const, void const*> >) (
    this=0x7ffff34d9800 <mallocMap>, __position=...)
    at /usr/local/prerequisites/package-install/gcc-4.8.2/include/c++/4.8.2/bits/stl_map.h:697
#4  0x00007fffef1f4d52 in new_free_hook (ptr=0x3031900, caller=0x7ffff7dc39ff) at utils/malloc_hook.h:89
#5  0x00007ffff7dc39ff in ?? () from /usr/local/prerequisites/versions/2.0/lib64/libcudart.so.5.5
#6  0x00007ffff7dc3bb7 in ?? () from /usr/local/prerequisites/versions/2.0/lib64/libcudart.so.5.5
#7  0x00007fffe8fb04d1 in __cudaUnregisterBinaryUtil ()
    at /usr/local/prerequisites/versions/2.0/include/crt/host_runtime.h:220
#8  0x00000037f10361bd in __cxa_finalize () from /lib64/libc.so.6
#9  0x00007fffe8ebdf46 in __do_global_dtors_aux () from /home/vlad/build/libbasic_lib.so
#10 0x00000000000000a2 in ?? ()
#11 0x0000000000000000 in ?? ()

anybody knows what might be the problem?

MoonBun
  • 4,322
  • 3
  • 37
  • 69
  • *Where* in the function do the crash happen? And how do you *use* these functions? – Some programmer dude Jul 29 '14 at 10:59
  • 1
    Hmmm.... what's with the C++ container mixed with loads of C memory handling and `printf`ing? – DevSolar Jul 29 '14 at 11:00
  • 1
    long story, lets just ignore the mix of c++ and c. @JoachimPileborg In the new_free_hook, the map.erase causes the seg fault. – MoonBun Jul 29 '14 at 11:09
  • 1
    Have you tried running it with gdb and/or valgrind? What's the stack trace when the segfault occurs? I am a bit worried that the map operations might call your hooks again, causing a possibly infinite loop - but that's a wild guess which may need testing. – CygnusX1 Jul 29 '14 at 11:18
  • As a sidenote, you're overrunning variable `it`. Bad idea... – Eitan T Jul 29 '14 at 11:19
  • @CygnusX1 no, this: __free_hook = old_free_hook; gives the hook back to the original free to avoid infinit loops, and in the end __free_hook = new_free_hook; gives it back to me. – MoonBun Jul 29 '14 at 11:19
  • Wouldn't it be simpler to use `mallocMap.erase(ptr);`? Not that it has anything to do with the segfault. – eerorika Jul 29 '14 at 11:20
  • @EitanT where do i overrun it? – MoonBun Jul 29 '14 at 11:20
  • @user2079303 it did before that, caused exactly the same error. – MoonBun Jul 29 '14 at 11:21
  • You explicitly declare `it` as an iterator, then you declare it as `auto it`. Just sayin'... – Eitan T Jul 29 '14 at 11:21
  • @EitanT you are right, i will fix it, but the error is still happen before that. – MoonBun Jul 29 '14 at 11:24
  • `free(ptr); if (ptr != 0)` causes undefined behaviour. You may not use the value of a pointer after freeing it. – M.M Jul 29 '14 at 11:39
  • Can you provide the stack trace before the crash? What is the size/contents of the map? What is the value of `ptr`? – Eitan T Jul 29 '14 at 11:39
  • adding an element to `mallocMap` will boil down to calling `malloc` to allocate more memory... could be problem – M.M Jul 29 '14 at 11:46
  • also, if the map was not empty at the point of `mallocMap = std::map();` , could be problem as old map may call `free` during its deallocation which then looks up the map currently being deleted – M.M Jul 29 '14 at 11:48
  • @MattMcNabb its not undefined behaviour. nobody uses its value, only the address it self. – MoonBun Jul 29 '14 at 13:33
  • @MattMcNabb I also tried to give all the hooks back and only only the one used correctly, but that only made the stack trace shorter with the same seg fault, not sure if that helped, i added the back trace. – MoonBun Jul 29 '14 at 13:39
  • @Vladp the value of a pointer *is* the address, it is undefined to use it after calling `free`. Move the `free` to the end of the function. – M.M Jul 29 '14 at 22:09
  • @Vladp the `memalign` hook adds to map so that needs to unhook `malloc` (and possibly `malloc` should unhook `memalign` too). However I would suggest replacing your map with a structure that has pre-allocated all its memory (either make a custom allocator for your map, or use a vector that you `reserve(5000)` or whatever before starting your debugging, and you manually keep it sorted). Then you can concentrate on debugging whatever you are debugging without the map interfering with it – M.M Jul 29 '14 at 22:11
  • @MattMcNabb I'm unhooking everything for each function now but still get the error. – MoonBun Jul 29 '14 at 22:54

0 Answers0