MEMORY_BASIC_INFORMATION access violation

I am working on a program that can search through memory of another process for a byte array.
Now I have succesfully done this, but I wanted to multithread it. So I though I would MT the ReadProcessMemory, for that I created a queue with MEMORY_BASIC_INFORMATION (or rather a smaller struct) as that was the data I needed to know the base address and region size.

So this is what exist in several threads:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
struct MemInfo {
    PVOID baseAddr;
    SIZE_T regionSize;
};

void scan_memory_func2(std::mutex& g_queue,
                              std::queue<MemInfo>& mem_queue,
                              std::mutex& g_found,
                              std::vector<const uint8_t*>& addresses_found,
                              const std::atomic<bool>& searching,
                              const std::vector<uint8_t>& byte_check,
                              HANDLE proc) {
    bool queue_empty = false;
    MemInfo info{};
    while (searching || !queue_empty) {
        {
            std::lock_guard<std::mutex> guard(g_queue);
            if (mem_queue.empty()) {
                queue_empty = true;
                continue;
            }
            else {
                info = mem_queue.front();
                mem_queue.pop();
                queue_empty = false;
            }
        }

        std::vector<uint8_t> mem_chunk{};
        size_t read;
        mem_chunk.reserve(info.regionSize);
        if (ReadProcessMemory(proc, info.baseAddr, mem_chunk.data(), info.regionSize, &read)) {
            auto start = mem_chunk.data(), end = start + read, pos = start;
            while ((pos = std::search(pos, end, byte_check.begin(), byte_check.end())) != end) {
                {
                    std::lock_guard<std::mutex> guard(g_found);
                    addresses_found.push_back(static_cast<const uint8_t*>(info.baseAddr) 
                                                                  + (pos - start));
                }
                pos += byte_check.size();
            }
        }
    }
}

The one that feeds the queue:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int main() {
    // Declear a bunch of variables
    for (size_t i = 0; i < MAX_T; i++) {
        worker_threads[i] = std::thread(scan_memory_func2,
                                        std::ref(g_queue),
                                        std::ref(mem_queue),
                                        std::ref(g_found),
                                        std::ref(addresses_found),
                                        std::ref(searching),
                                        std::ref(byte_check),
                                        m_proc);
    }

    while (address < address_high && VirtualQueryEx(m_proc, address, &info, sizeof(info))) {
        if ((info.State == MEM_COMMIT) && (info.Protect & pmask) && !(info.Protect & PAGE_GUARD)) {
            mem_queue.push({info.BaseAddress, info.RegionSize});
        }
        address += info.RegionSize;
    }
    searching = false;
    for (auto&& i : worker_threads) {
        if (i.joinable()) {
            i.join();
        }
    }

    return addresses_found;
}


So what __occaonally__ happend is that when I get the front of the queue to a variable in the thread, I get an access violation

info = mem_queue.front();

So I am wondering what I might be doing wrong?
This happens more often if I compile in release, so it makes me thing it is speed related.
I hope someone can give me some insight.


Last edited on
So I am wondering what I might be doing wrong?
Line 16. You need the mutex for synchronizing two threads. Therefore you need to lock the mutex within the main thread as well.
The way you're using std::vector::reserve() is incorrect. reserve() is not required to do anything, so there's no guarantee that when you call mem_chunk.data() you'll get a valid pointer. You should use resize() instead.

However, I don't think that's causing the issue you're seeing. What you're describing sounds like typical memory corruption. The thing about memory corruption is that where the program crashes actually tells you very little about who made the program crash. The code you've posted seems fine to me (other than what I've mentioned which is relatively minor). The way the program is crashing, you're obviously making an error in the you haven't shown. We'll need to see the whole thing to be able to help.
Thank you @coder777, that seem to have fixed it. I must have completely missed it. Thank you so much for your sharp eyes :D

@helios You bring out a good point, and I will change it to resize
Damn. How'd I miss that?

You could also populate the queue before starting the threads.
Registered users can post here. Sign in or register to post.