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());
精彩评论