Weirdness in /proc/<pid>/maps and /proc/<pid>/stat.

From: Robin Holt
Date: Tue Apr 27 2010 - 14:53:55 EST



With commit d899bf7b, the behavior of field 28 of /proc/<pid>/stat
was changed as was /proc/<pid>/maps. I don't know if that change was
correct, but its resulting behavior is much more difficult to explain.
I was wondering if we could determine what the "correct" behavior is
before I spend much more time trying to give it the wrong behavior.

My test program is attached below. Essentially:
fork() -> pthread_create() -> fork()

x86_64 2.6.32 stable kernel:
Step stat-28 maps-threadstack
p (parent) 0x7fff5607ddc0 N/A
c (child) 0x7fff55c7dc50 N/A
ppthread 0x7f2cf5c9bff0 0x7f2cf5c9d000:007feff0
ppthread+fork 0x7f2cf589be30 0x7f2cf5c9d000:003fee30
cpthread 0x7f2cf589be30 0x7f2cf5c9d000:007feff0
cpthread+fork 0x7f2cf589be30 0x7f2cf5c9d000:003fee30
Note: For all of the above, the /proc/<pids>/task/*/maps files had the
stack line like:
7fff55c7d000-7fff56081000 rw-p 00000000 00:00 0 [stack]

The problems I see are:
1) In the fork() case, we are using the current userland stack
pointer for task->stack_start. This appears wrong as the
function which called fork() may be returned to and may
further return to higher level callers, finding sp now
beyond the value reported in /proc/self/stat. Additionally,
the value reported for the child of the fork has no relationship
to the stack size rlimit any longer.

2) In the pthread + fork case, in addition to the problem
above, the size information in /proc/self/maps
is incorrect as it does not take into consideration
the same return paths.

The problem I am running into is coming up with any way to
make the task->stack_start value usable.

Thanks,
Robin Holt

------------------------------- Example --------------------------------
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <asm-generic/unistd.h>

#include <sys/types.h>

pid_t
my_fork(void)
{
char test_array[2097152];
pid_t child;

printf("pid %d my_fork array at %p\n", getpid(), test_array);
child = fork();
return child;
}

void
*as_pthread(void *ignore)
{
char test_array[2097152];

printf("pid %d pthread array at %p\n", getpid(), test_array);
my_fork();
sleep(600);

return NULL;
}

int
main (int argc, char **argv)
{
char test_array[2097152];
pid_t child;
pthread_t pt;

printf("pid %d is parent 0x%p\n", getpid(), test_array);

child = my_fork();
if (child)
printf("child of main is %d\n", child);
else
sleep(1);
pthread_create(&pt, NULL, as_pthread, NULL);
sleep(600);
return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/