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:
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.
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.