Нарушение прав доступа C ++ (удаление элементов в векторе) - PullRequest
0 голосов
/ 14 января 2011

Я пытаюсь удалить несоответствующие результаты из сканера памяти, который я пишу на C ++, на практике.При первоначальном сканировании памяти все результаты сохраняются в векторе _results.

Позже, _results сканируется снова и должен удалять элементы, которые больше не соответствуют.

Ошибка:

Необработанное исключение в 0x004016f4 в .exe: 0xC0000005: расположение чтения нарушения доступа 0x0090c000.

// Receives data

DWORD buffer;

for (vector<memblock>::iterator it = MemoryScanner::_results.begin(); it != MemoryScanner::_results.end(); ++it) {
    // Reads data from an area of memory into buffer
    ReadProcessMemory(MemoryScanner::_hProc, (LPVOID)(*it).address, &buffer, sizeof(buffer), NULL);

    if (value != buffer) {
        MemoryScanner::_results.erase(it); // where the program breaks
    }
}

Ответы [ 3 ]

5 голосов
/ 14 января 2011

Стирание элементов из std::vector<T> сделает недействительным итератор it, поскольку объект std::vector<T> будет перемещать элементы вокруг, чтобы сохранить непрерывность основного массива после удаления элемента.

К счастью, vector<T>::erase() возвращаетновый действительный итератор, чтобы вы не пытались разыменовать неверный итератор:

DWORD buffer;
vector<memblock>::iterator it = MemoryScanner::_results.begin(); 
while(it != MemoryScanner::_results.end())
{
    ReadProcessMemory(MemoryScanner::_hProc, (LPVOID)(*it).address,
        &buffer, sizeof(buffer), NULL);
    if (value != buffer)
    {
        it = MemoryScanner::_results.erase(it);
    }
    else
    {
        ++it;
    }
}

Другой способ удаления элементов в векторе

Рассматривали ли вы использование стирание-удаление идиома ?

struct RemoveNonMatches
{
public:
    RemoveNonMatches(HANDLE p, DWORD v) : proc(p) val(v) {}

    bool operator()(const memblock& obj)
    {
        DWORD buffer;
        ReadProcessMemory(proc, static_cast<LPVOID>(obj.address),
            &buffer, sizeof(buffer), NULL);
        return (buffer != val);
    }

private:
    HANDLE proc
    DWORD val;
};

// ...

MemoryScanner::_results.erase
(
    std::remove_if
    (
        MemoryScanner::_results.begin(),
        MemoryScanner::_results.end(),
        RemoveNonMatches(MemoryScanner::_hProc, value)
    ),
    MemoryScanner::_results.end()
);
1 голос
/ 14 января 2011

vector::erase делает недействительным итератор, который вы передали erase().Затем вы пытаетесь увеличить его.UB следует.

0 голосов
/ 14 января 2011

Версия std::remove_if, для полноты:

bool has_bad_memory_contents(const memblock& block) {
    DWORD buffer;
    ReadProcessMemory(
        MemoryScanner::_hProc, (LPVOID)block.address,
        &buffer, sizeof(buffer), NULL
    );
    return buffer != value;
}

std::vector<memblock>& r = MemoryScanner::_results;
r.erase(std::remove_if(r.begin(), r.end(), has_bad_memory_contents), r.end());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...