Why is Dr Memory reporting freed memory errors when I haven't freed any memory?

281 Views Asked by At

The following code

#include <vector>
#include <string>
#include <iostream>

struct Type
{
    std::string a;
};

int main()
{
    std::vector<unsigned char> data;

    data.resize(sizeof(Type));

    Type* a = new (&data[0]) Type({"something"});

    data.resize(sizeof(Type)*2);

    Type* b = new (&data[sizeof(Type)]) Type({"else"});

    Type* ts = reinterpret_cast<Type*>(&data[0]);

    for(std::size_t i = 0; i < 2; ++i)
    {
        std::cout << ts[i].a << std::endl;
        ts[i].~Type();
    }

    return 0;
}

produces this output from Dr Memory

Dr. Memory version 2.2.0 build 1 built on Jul  1 2019 00:42:20
Windows version: WinVer=105;Rel=1909;Build=18363;Edition=Enterprise
Dr. Memory results for pid 14664: "CPPTests.exe"
Application cmdline: "bin/Debug/CPPTests.exe -callstack_max_frames 40 -malloc_max_frames 40 -free_max_frames 40"
Recorded 117 suppression(s) from default C:\Program Files (x86)\Dr. Memory\bin\suppress-default.txt

Error #1: UNADDRESSABLE ACCESS of freed memory: reading 0x01750568-0x01750569 1 byte(s)
# 0 msvcrt.dll!_fwrite_nolock
# 1 msvcrt.dll!fwrite    
# 2 libstdc++-6.dll!?                +0x0      (0x6fe5cf56 <libstdc++-6.dll+0x1cf56>)
# 3 libstdc++-6.dll!?                +0x0      (0x6ff23d80 <libstdc++-6.dll+0xe3d80>)
# 4 _fu0___ZSt4cout                   [C:/tests.cpp:26]
# 5 __tmainCRTStartup                 [D:/mingwbuild/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:335]
# 6 KERNEL32.dll!BaseThreadInitThunk +0x18     (0x75306359 <KERNEL32.dll+0x16359>)
Note: @0:00:00.608 in thread 3732
Note: next higher malloc: 0x01750598-0x017505c8
Note: prev lower malloc:  0x01750468-0x0175046b
Note: 0x01750568-0x01750569 overlaps memory 0x01750560-0x01750578 that was freed here:
Note: # 0 replace_operator_delete                              [d:\drmemory_package\common\alloc_replace.c:2975]
Note: # 1 __gnu_cxx::new_allocator<>::deallocate               [C:/MSYS2-32/mingw32/include/c++/10.1.0/ext/new_allocator.h:133]
Note: # 2 std::allocator_traits<>::deallocate                  [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/allocator.h:187]
Note: # 3 std::_Vector_base<>::_M_deallocate                   [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:354]
Note: # 4 std::vector<>::_M_default_append                     [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/vector.tcc:675]
Note: # 5 std::vector<>::resize                                [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:940]
Note: instruction: movsx  (%eax) -> %eax

Error #2: INVALID HEAP ARGUMENT to free 0x01750568
# 0 replace_operator_delete                                   [d:\drmemory_package\common\alloc_replace.c:2975]
# 1 __gnu_cxx::new_allocator<>::deallocate                    [C:/MSYS2-32/mingw32/include/c++/10.1.0/ext/new_allocator.h:133]
# 2 std::allocator_traits<>::deallocate                       [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/allocator.h:187]
# 3 std::__cxx11::basic_string<>::_M_destroy                  [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/basic_string.h:237]
# 4 std::__cxx11::basic_string<>::_M_dispose                  [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/basic_string.h:232]
# 5 std::__cxx11::basic_string<>::~basic_string               [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/basic_string.h:658]
# 6 Type::~Type                                               [C:/tests.cpp:5]
# 7 _fu0___ZSt4cout                                           [C:/tests.cpp:27]
# 8 __tmainCRTStartup                                         [D:/mingwbuild/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:335]
# 9 KERNEL32.dll!BaseThreadInitThunk                         +0x18     (0x75306359 <KERNEL32.dll+0x16359>)
Note: @0:00:00.743 in thread 3732
Note: next higher malloc: 0x01750598-0x017505c8
Note: prev lower malloc:  0x01750468-0x0175046b
Note: 0x01750568-0x01750568 overlaps memory 0x01750560-0x01750578 that was freed here:
Note: # 0 replace_operator_delete                              [d:\drmemory_package\common\alloc_replace.c:2975]
Note: # 1 __gnu_cxx::new_allocator<>::deallocate               [C:/MSYS2-32/mingw32/include/c++/10.1.0/ext/new_allocator.h:133]
Note: # 2 std::allocator_traits<>::deallocate                  [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/allocator.h:187]
Note: # 3 std::_Vector_base<>::_M_deallocate                   [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:354]
Note: # 4 std::vector<>::_M_default_append                     [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/vector.tcc:675]
Note: # 5 std::vector<>::resize                                [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:940]

===========================================================================
FINAL SUMMARY:

DUPLICATE ERROR COUNTS:

SUPPRESSIONS USED:

ERRORS FOUND:
      1 unique,     1 total unaddressable access(es)
      0 unique,     0 total uninitialized access(es)
      1 unique,     1 total invalid heap argument(s)
      0 unique,     0 total GDI usage error(s)
      0 unique,     0 total handle leak(s)
      0 unique,     0 total warning(s)
      0 unique,     0 total,      0 byte(s) of leak(s)
      0 unique,     0 total,      0 byte(s) of possible leak(s)
ERRORS IGNORED:
      1 potential error(s) (suspected false positives)
         (details: C:\AppData\Roaming\Dr. Memory\DrMemory-CPPTests.exe.14664.000\potential_errors.txt)
      3 unique,     9 total,    154 byte(s) of still-reachable allocation(s)
         (re-run with "-show_reachable" for details)
Details: C:\AppData\Roaming\Dr. Memory\DrMemory-CPPTests.exe.14664.000\results.txt

But I was of the impression that this was all fine as I am not keeping any pointers into the vector after it's resized. What am I not understanding?

1

There are 1 best solutions below

4
eerorika On

when I haven't freed any memory?

Sure you have. You (potentially) free memory right here:

data.resize(sizeof(Type)*2);
ts[i].~Type();
} // closes main

The issue is that when the vector reallocates memory, it will copy the unsigned char elements elsewhere. This doesn't work for the Type object created in that memory because Type is not trivially copyable.