clinuxmemorygarbage-collectionstack

Variable address does not fall within the stack range in /proc/self/maps


I have a very simple program to test this:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    int ss;
    int xx = system("cat /proc/self/maps | grep stack");
    printf("&ss=%p\n", &ss);
    return 0;
}

I compile and run this (on Linux, on an x86_64 cpu), I get something like this:

7ffc63ee7000-7ffc63f09000 rw-p 00000000 00:00 0                          [stack]
&ss=0x7ffe3e13d8a0

If you do the math, you see that 0x7ffe3e13d8a0 does not fall within the 7ffc63ee7000-7ffc63f09000 range. No matter how many times I run this, this seems to be the case. I can't understand why.

I've seen a similar question on SO already: Address of local variable not within the address range of stack shown by smaps

The provided answers don't work for me:

  1. obviously there are no threads in this program.
  2. no coroutine style programming, longjmp, etc.

Any help would be greatly appreciated.

Just to clarify the reason I need to do this. I'm writing a conservative garbage collector, and I want to get the range of stack to scan, by obtaining the address of a variable in main and another in the current function.


Solution

  • The memory map produced by system("cat /proc/self/maps | grep stack") is not that of your program, but rather that of the cat process that opens the file /proc/self/maps.

    You should construct the command line from the pid of your own process:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[]) {
        int ss;
        char cmd[64];
        snprintf(cmd, sizeof cmd, "cat /proc/%d/maps | grep stack", getpid());
        system(cmd);
        printf("&ss=%p\n", (void *)&ss);
        return 0;
    }
    

    Output:

    chqrlie@linuxbox:~/dev/stackoverflow$ ./test
    7ffd9ffb5000-7ffd9ffd6000 rw-p 00000000 00:00 0                          [stack]
    &ss=0x7ffd9ffd368c
    

    For your GC purpose, using /proc/self/maps would be OK since you would be opening the pseudo-file from the same process. Note however that this feature is linux specific, other unix or posix systems might not offer it, have a different API to get the info or the info might not be available at all.

    Here is an implementation with a single process:

    #include <errno.h>
    #include <stdio.h>
    #include <string.h>
    
    int main(int argc, char *argv[]) {
        FILE *fp = fopen("/proc/self/maps", "r");
        if (fp) {
            char buf[200];
            int ss;
            while (fgets(buf, sizeof buf, fp)) {
                if (strstr(buf, "stack"))
                    fputs(buf, stdout);
            }
            fclose(fp);
            printf("&ss=%p\n", (void *)&ss);
            return 0;
        } else {
            fprintf(stderr, "cannot open /proc/self/maps: %s\n", strerror(errno));
            return 1;
        }
    }
    

    Also note another non obvious fact: in your test, you get different ranges for your process and cat, not so much because they are different processes, but mainly because the OS performs address space randomisation as a countermeasure against simple attack vectors. The addresses are in separate virtual memory spaces, so they might have matched by coincidence and they probably would have on older 32-bit linux systems.