开发者

Access violation C++ (Deleting items in a vector)

开发者 https://www.devze.com 2023-02-04 08:57 出处:网络
I\'m trying to remove non-matching results from a memory scanner I\'m writing in C++ as practice. When the memory is initially scanned, all results are stored into the _results vector.

I'm trying to remove non-matching results from a memory scanner I'm writing in C++ as practice. When the memory is initially scanned, all results are stored into the _results vector.

Later, the _results are scanned again and should erase items that no longer match.

The error:

Unhandled exception at 0x004016f4 in 开发者_开发技巧.exe: 0xC0000005: Access violation reading location 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
    }
}


Erasing elements from a std::vector<T> will invalidate the it iterator since the std::vector<T> object will shift elements around to keep the underlying array contiguous after deleting an item.

Fortunately, vector<T>::erase() returns a new, valid iterator so that you don't end up trying to dereference an invalid iterator:

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;
    }
}

Another way to delete items in a vector

Have you considered using the erase-remove idiom?

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()
);


vector::erase invalidates the iterator you passed to erase(). You then attempt to increment it. UB ensues.


The std::remove_if version, for completeness:

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());
0

精彩评论

暂无评论...
验证码 换一张
取 消