Обращаюсь ли я к уже освобожденной памяти или DrMemory в этом случае сообщает некорректно? - PullRequest
1 голос
/ 28 мая 2020

У меня есть следующая программа:

#include <vector>

struct Comp1
{
    float x;
    std::vector<int> vec;
};

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

    data.resize(sizeof(Comp1));

    Comp1* ptr1 = new (&data[0]) Comp1({.3f,{3,4,2,1}});

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

    Comp1* ptr2 = new (&data[sizeof(Comp1)]) Comp1({.2f,{2,3,4}});

    ptr1->~Comp1();

    std::vector<char>::iterator itrStart = data.begin();
    std::vector<char>::iterator itrEnd = itrStart + sizeof(Comp1);
    data.erase(itrStart,itrEnd);

    ptr2 = reinterpret_cast<Comp1*>(&data[0]);

    ptr2->~Comp1();

    return 0;
}

Компилируется без проблем. Выполняется на моей машине без проблем. Запустите его через GDB, и ничего не сообщается. Насколько я понимаю, все, что я сделал выше, правильно (за исключением, может быть, мне не хватает использования std::launder, когда я reinterpret_cast от char* до Comp1*?).

Однако вызов DrMemory в этой программе с помощью:

drmemory.exe test.exe -callstack_max_frames 40 -malloc_max_frames 40 -free_max_frames 40

дает мне следующий вывод ошибки:

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 20424: "test.exe"
Application cmdline: "bin/test.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 0x01975230-0x01975234 4 byte(s)
# 0 std::vector<>::~vector               [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:680]
# 1 Comp1::~Comp1                        [C:/Tests/test.cpp:3]
# 2 main                                 [C:/Tests/test.cpp:21]
Note: @0:00:01.329 in thread 2068
Note: next higher malloc: 0x01975258-0x01975268
Note: 0x01975230-0x01975234 overlaps memory 0x01975228-0x01975238 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: mov    0x04(%edx) -> %ecx

Error #2: UNADDRESSABLE ACCESS of freed memory: reading 0x0197522c-0x01975230 4 byte(s)
# 0 std::vector<>::~vector               [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:680]
# 1 Comp1::~Comp1                        [C:/Tests/test.cpp:3]
# 2 main                                 [C:/Tests/test.cpp:21]
Note: @0:00:01.447 in thread 2068
Note: next higher malloc: 0x01975258-0x01975268
Note: 0x0197522c-0x01975230 overlaps memory 0x01975228-0x01975238 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: mov    (%edx) -> %edx

Error #3: UNADDRESSABLE ACCESS of freed memory: reading 0x01975234-0x01975238 4 byte(s)
# 0 std::_Vector_base<>::~_Vector_base               [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:336]
# 1 std::vector<>::~vector                           [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:683]
# 2 Comp1::~Comp1                                    [C:/Tests/test.cpp:3]
# 3 main                                             [C:/Tests/test.cpp:21]
Note: @0:00:01.471 in thread 2068
Note: next higher malloc: 0x01975258-0x01975268
Note: 0x01975234-0x01975238 overlaps memory 0x01975228-0x01975238 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: mov    0x08(%eax) -> %edx

Error #4: UNADDRESSABLE ACCESS of freed memory: reading 0x0197522c-0x01975230 4 byte(s)
# 0 std::_Vector_base<>::~_Vector_base               [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:336]
# 1 std::vector<>::~vector                           [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:683]
# 2 Comp1::~Comp1                                    [C:/Tests/test.cpp:3]
# 3 main                                             [C:/Tests/test.cpp:21]
Note: @0:00:01.489 in thread 2068
Note: next higher malloc: 0x01975258-0x01975268
Note: 0x0197522c-0x01975230 overlaps memory 0x01975228-0x01975238 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: mov    (%eax) -> %ecx

Error #5: UNADDRESSABLE ACCESS of freed memory: reading 0x0197522c-0x01975230 4 byte(s)
# 0 std::_Vector_base<>::~_Vector_base               [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:335]
# 1 std::vector<>::~vector                           [C:/MSYS2-32/mingw32/include/c++/10.1.0/bits/stl_vector.h:683]
# 2 Comp1::~Comp1                                    [C:/Tests/test.cpp:3]
# 3 main                                             [C:/Tests/test.cpp:21]
Note: @0:00:01.504 in thread 2068
Note: next higher malloc: 0x01975258-0x01975268
Note: 0x0197522c-0x01975230 overlaps memory 0x01975228-0x01975238 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: mov    (%eax) -> %edx

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

DUPLICATE ERROR COUNTS:

SUPPRESSIONS USED:

ERRORS FOUND:
      5 unique,     5 total unaddressable access(es)
      0 unique,     0 total uninitialized access(es)
      0 unique,     0 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:
      2 potential error(s) (suspected false positives)
         (details: C:\Users\david\AppData\Roaming\Dr. Memory\DrMemory-test.exe.20424.000\potential_errors.txt)
      8 unique,    14 total,  19443 byte(s) of still-reachable allocation(s)
         (re-run with "-show_reachable" for details)
Details: C:\Users\david\AppData\Roaming\Dr. Memory\DrMemory-test.exe.20424.000\results.txt

Я что-то пропустил в своей программе, или это случай, когда DrMemory не могу понять, что делаю?

Ответы [ 2 ]

5 голосов
/ 28 мая 2020

В вашем коде вы делаете

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

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

ptr1->~Comp1();

обращается к недопустимому объекту, и у вас неопределенное поведение. Это не утечка памяти, а проблема с незаконным доступом, и это то, что диагностирует доктор Память.

0 голосов
/ 28 мая 2020

(Слишком долго для комментария.)

Если вы хотите, чтобы буфер резервного хранилища построенных на месте объектов не перемещался, вы можете использовать вектор вектора байтов. Если вам нужна последовательная память (скажем, для расположения кеша), это не сработает.

#include <vector>

using std::vector;

struct Comp1 {
    float x;
    vector<int> vec;
};

int main() {
    vector<vector<char>> data;

    data.push_back(vector<char>(sizeof(Comp1)));
    Comp1* ptr1 = new (&data[0][0]) Comp1({.3f,{3,4,2,1}});

    data.push_back(vector<char>(sizeof(Comp1)));

    Comp1* ptr2 = new (&data[1][0]) Comp1({.2f,{2,3,4}});

    ptr1->~Comp1();

    auto itrStart = data.begin();
    auto itrEnd = itrStart + 1;
    data.erase(itrStart, itrEnd);

    ptr2->~Comp1();
}
...