c++ memory error when using malloc/realloc/free on

2019-03-04 06:35发布

问题:

I wrote a small piece of code like this:

template <class T>
void
test()
{
    T* ptr = nullptr;

    ptr = (T*)malloc(1 * sizeof(T));

    new ((void*)ptr) T(T());

    ptr = (T*)realloc(ptr, 2 * sizeof(T));

    new ((void*)(ptr + 1)) T(T());

    (ptr)->~T();
    (ptr + 1)->~T();

    free(ptr);
}

struct foo
{
    foo() : ptr(malloc(10)) {}
    ~foo() { free(ptr); } 
    void* ptr;
};

int
main()
{ 
    test<int>(); // this is ok
    test<foo>(); // this is ok
    test<std::string>(); // memory error :(

    return 0;
}; 

When T is [int] or [foo], everything works fine. But using [std::string] as T causes valgrind to report memory errors like this:

==18184== Memcheck, a memory error detector
==18184== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==18184== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==18184== Command: ./a.out
==18184== 
==18184== Invalid free() / delete / delete[] / realloc()
==18184==    at 0x4C2C20A: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18184==    by 0x401074: void test<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >() (tmp.cpp:26)
==18184==    by 0x400CFC: main (tmp.cpp:44)
==18184==  Address 0x5a89e70 is 16 bytes inside a block of size 32 free'd
==18184==    at 0x4C2CC37: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18184==    by 0x401042: void test<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >() (tmp.cpp:22)
==18184==    by 0x400CFC: main (tmp.cpp:44)
==18184==  Block was alloc'd at
==18184==    at 0x4C2AB8D: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18184==    by 0x40100F: void test<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >() (tmp.cpp:18)
==18184==    by 0x400CFC: main (tmp.cpp:44)
==18184== 
==18184== 
==18184== HEAP SUMMARY:
==18184==     in use at exit: 0 bytes in 0 blocks
==18184==   total heap usage: 9 allocs, 10 frees, 72,856 bytes allocated
==18184== 
==18184== All heap blocks were freed -- no leaks are possible
==18184== 
==18184== For counts of detected and suppressed errors, rerun with: -v
==18184== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

why only [std::string] leads to memory problem while [foo] also has malloc/free in both ctor & dtor ?

I'm using g++ 6.2.1 and valgrind 3.12.0

回答1:

malloc(), free(), and realloc() are C library functions, that know absolutely nothing about C++ classes, their constructors, and destructors.

You are using malloc() with placement new to construct a std::string using malloc-ed memory. This is fine.

But then, you're using realloc() to reallocate the allocated memory.

Copying/moving C++ objects in memory must be done using the respective objects' copy/move constructors. Copying/moving C++ objects in memory cannot be done with realloc().

The only way to do this is to malloc() a new memory block, use placement new to invoke the objects' copy/move constructors in order to copy/move them into the new memory block, and finally invoke the destructor of the objects in the old memory block, after which it can be free()-ed.



回答2:

realloc is not compatible with non-POD types.

Because it can move things in memory without the moved objects being aware of it.