1

From inside a Linux process, one could read from /proc/self/maps to see a description of its address space. For example,

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

void print_maps() {
    int fd = open("/proc/self/maps", O_RDONLY);
    char buf[512];
    int rc;
    fflush(stdout); //Not necessary for this example, but I usually
                    //include before directly writing to STDOUT_FILENO
    while ((rc = read(fd, buf, sizeof(buf))) > 0) {
        write(STDOUT_FILENO, buf, rc);
    }
    close(fd);
}

int main(void) {

    print_maps();
    return 0;
}

For me this prints (I ran this on repl.it):

559de76b2000-559de76b3000 r-xp 00000000 00:12bf 411                      /home/runner/crt/main
559de78b2000-559de78b3000 r--p 00000000 00:12bf 411                      /home/runner/crt/main
559de78b3000-559de78b4000 rw-p 00001000 00:12bf 411                      /home/runner/crt/main
7f259008a000-7f2590271000 r-xp 00000000 08:01 4133143                    /lib/x86_64-linux-gnu/libc-2.27.so
7f2590271000-7f2590471000 ---p 001e7000 08:01 4133143                    /lib/x86_64-linux-gnu/libc-2.27.so
7f2590471000-7f2590475000 r--p 001e7000 08:01 4133143                    /lib/x86_64-linux-gnu/libc-2.27.so
7f2590475000-7f2590477000 rw-p 001eb000 08:01 4133143                    /lib/x86_64-linux-gnu/libc-2.27.so
7f2590477000-7f259047b000 rw-p 00000000 00:00 0 
7f259047b000-7f25904a4000 r-xp 00000000 08:01 4133125                    /lib/x86_64-linux-gnu/ld-2.27.so
7f25906a2000-7f25906a4000 rw-p 00000000 00:00 0 
7f25906a4000-7f25906a5000 r--p 00029000 08:01 4133125                    /lib/x86_64-linux-gnu/ld-2.27.so
7f25906a5000-7f25906a6000 rw-p 0002a000 08:01 4133125                    /lib/x86_64-linux-gnu/ld-2.27.so
7f25906a6000-7f25906a7000 rw-p 00000000 00:00 0 
7ffc92553000-7ffc92574000 rw-p 00000000 00:00 0                          [stack]
7ffc925f4000-7ffc925f7000 r--p 00000000 00:00 0                          [vvar]
7ffc925f7000-7ffc925f8000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

In theory, you could parse this text and have a way of knowing what virtual addresses are free. But is this maps file complete? Is there a more idiomatic way of asking the Linux kernel to indicate some free region in your own virtual address space?

Marco Merlini
  • 875
  • 7
  • 29
  • 2
    Use mmap. That will also reserve the memory address, avoiding TOCTOU race conditions. – rici May 22 '21 at 21:07
  • The reason to find a free area is because I want to do two (separate) mmap calls to map two regions into one contiguous block. A single call to mmap guarantees that your map is made somewhere, but not necessarily at the address you asked for. – Marco Merlini May 22 '21 at 21:14
  • You can use mprotect to change (some) protections on a subregion. Or you can remap with MAP_FIXED; on Linux, at least, that will work as expected if the requested address is correctly aligned. – rici May 22 '21 at 22:10
  • 1
    _The reason to find a free area is because I want to do two (separate) mmap calls to map two regions into one contiguous block._ Might I ask: _Why?_ To make sense, this means the first region must be an exact page length (with _no_ gap). And, how do you guarantee that? What is the advantage of a single mapping vs. two mappings for your use case? To me, this is beginning to sound like an XY problem: https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem – Craig Estey May 22 '21 at 23:12
  • That's fair; feel free to vote-close. For reference I did just find a solution to the Y part of the problem here: https://stackoverflow.com/a/28576674/2737696 – Marco Merlini May 23 '21 at 04:07
  • @MarcoMerlini: Would you like to post your own answer explaining what you learned? – Nate Eldredge May 23 '21 at 15:44

1 Answers1

0

You say:

In theory, you could parse this text and have a way of knowing what virtual addresses are free. But is this maps file complete? Is there a more idiomatic way of asking the Linux kernel to indicate some free region in your own virtual address space?

Yes, in theory and in practice, indeed is the approach followed by linux to offer you info about your process image. You can, and you should.

It should be complete, as it's only purpose (and this requires code in the kernel to provide you this information, and in this simple format) is to give you the information.

I'm afraid this is the best. You get directly the numbers from the kernel table it uses to map your process....so no better info you can guess. The other regions (the not occupied regions in your virtual address space) are not free. They are simply not assigned, and any trial to referr to them will end you in a SIGSEGV violation. This is a protection mechanism for you to detect you are doing something nasty in your code, and it is the most the operating system can allow for you as once it gives you memory it's use is your concern and nothing can prevent your memory to be used the way you want.

Well, I dont' know if this is the kind of answer you expected, but there's nothing else, so you have to pass through it. Reading a /proc file and converting ascii strings into numbers is cheap in today's code, so you don't need to think in a better way to do. Just scanf() or fgets() it, and convert.

It is not clear to me why are you asking for free zones (nonallocated) in your virtual address space. To get them occupied you need to perform some operating system call, and this requires a call that normally accepts allowing the kernel to decide what is the best place to use (normally there's a way for you to specify a hint but as there are normally hardware limitation on where to put it, the parameter you use is obeyed.... or not)

In today's operating systems, there's a vast allocation space for the kernel to have problems allocating a place to give you a memory region, so the best is to let the system to do it for you, and no need to calculate what has been allocated and what hasn't.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31