Anonymous Entity
Anonymous Entity

Reputation: 3350

mprotect fails after some number of calls

I am trying to write a program where I allocate a block of memory, and then selectively change the protection of page-sized and page-aligned subsets of the block. But when I try to call mprotect on parts of the memory that are > 8 pages into the block, mprotect fails with the error "Cannot allocate memory".

Here is a minimal, complete, and verifiable example that reproduces the problem:

#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <cerrno>
#include <cstring>
#include <iostream>

int main() {
    const int n_pages = 12;
    const int page_size = sysconf(_SC_PAGE_SIZE);   // 4096
    const int block_size = n_pages * page_size;     // 65536

    char* block_addr = (char*)aligned_alloc(page_size, block_size);
    char* chunks[n_pages];
    char* pointer = block_addr;

    for (int n = 0; n < n_pages; n++) {
        pointer = pointer + (n * page_size);
        chunks[n] = pointer;
    }
    std::cout << "Set chunks read-only.\n";
    for (int n = 0; n < n_pages; n++) {
        if (mprotect(chunks[n], page_size, PROT_READ) != 0) {
            std::cerr << n+1 << '/' << n_pages << ' '
                      << "mprotect failed: " << std::strerror(errno) << '\n';
        }
    }
    std::cout << "Set chunks read/write.\n";
    for (int n = 0; n < n_pages; n++) {
        if (mprotect(chunks[n], page_size, PROT_READ|PROT_WRITE) != 0) {
            std::cerr << n+1 << '/' << n_pages << ' '
                      << "mprotect failed: " << std::strerror(errno) << '\n';
        }
    }
    free(block_addr);
}

This consistently fails for chunks n>8, giving the following message:

Set chunks read-only.
9/12 mprotect failed: Cannot allocate memory
10/12 mprotect failed: Cannot allocate memory
11/12 mprotect failed: Cannot allocate memory
12/12 mprotect failed: Cannot allocate memory
Set chunks read/write.
9/12 mprotect failed: Cannot allocate memory
10/12 mprotect failed: Cannot allocate memory
11/12 mprotect failed: Cannot allocate memory
12/12 mprotect failed: Cannot allocate memory

I found a question in which the OP seems to get the same error as I, where David Hammen usefully provides some hints to the source of the problem, but I don't really understand what he is talking about. Unfortunately OP doesn't provide their code so we can't know exactly what they were doing or how they fixed it.

So basically my question is: Why does mprotect produce that error, and how can I fix it?

Upvotes: 0

Views: 618

Answers (1)

melpomene
melpomene

Reputation: 85827

    pointer = pointer + (n * page_size);

This line looks very suspicious. It should probably be either

    pointer = block_addr + (n * page_size);

or

    chunks[n] = pointer;  // need to assign to chunks[n] first
    pointer = pointer + page_size;

Otherwise pointer will walk off (in steps of 0, 1 (= 0 + 1), 3 (= 0 + 1 + 2), 6 (= 0 + 1 + 2 + 3), ...) into memory that doesn't belong to your process because you didn't allocate it (i.e. it's "unmapped"). This would explain why mprotect fails for the last couple of chunks.

Upvotes: 2

Related Questions