Mike - Nice catch. Some commenting suggestions below.
Reviewed-by: Steven J. Magnani <[email protected]> On Tue, 2011-02-22 at 00:31 +0000, [email protected] wrote: > Message: 2 > Date: Mon, 21 Feb 2011 17:51:04 -0500 > From: Mike Frysinger <[email protected]> > To: [email protected] > Cc: [email protected] > Subject: [PATCH] linuxthreads.old: fix nommu initial thread stack > detection > Message-ID: <[email protected]> > > Because the nommu address space is flat, and the application stack can > literally be located anywhere, we cannot rely on the assumptions that the > mmu port gets away with. Namely, that the first thread's stack lives at > the top of memory and nothing will be created above it. > > Currently, the code rounds the current stack up a page and sets that as > the "top" of the stack, and then marks the "bottom" of the stack as "1". > Then as new threads are created, this assumption is further refined by > slowly backing off the "bottom" when a new stack is created within the > range of the initial stack. > > Simple ascii example (tid0 is the initial thread): > > 1 thread: > [bos tid0 stack tos] > > 2 threads: > [ tid0 stack ] > [tid1 stack] > > 3 threads: > [ tid0 stack ] > [tid1 stack] > [tid2 stack] > > As you can kind of see, this algorithm operates on one basic assumption: > the initial top of stack calculation is the absolute top of the stack. > While this assumption was fairly safe in the original nommu days of yore > where the only file format was FLAT (which defaults to a 4KiB stack -- > exactly 1 page), and memory was fairly tight, we can see that this falls > apart pretty quickly as soon as the initial stack is larger than a page. > > The issue that crops up now is simple to hit: start an application with > an 8KiB stack, execute some functions that put pressure on the stack so > that it exceeds 4KiB, then start up some threads. The initial tos will > be rounded up by a page, but this is actually the middle of the stack. > Now when the initial thread returns from its functions (thus unwinding > the stack) and tries to call something which calls back into libpthread, > the thread_self() func fails to detect itself as the initial thread as > the current stack is now above the tos. The __pthread_find_self() func > kicks in, walks all the thread arrays, fails to find a hit, and then > walks into uninitialized memory for the thread descriptor. Use of this > garbage memory has obvious results -- things fall down & go boom. > > To address this, I extend the current algorithm to automatically scale > back both the bottom and the top stack limits of the initial thread. > We use the current stack pointer at "thread boot time" only as a single > known point. The initial thread stack bottom is set to the bottom of > memory and the initial thread stack top is set to the top of memory. > Then as we create new stack threads, we figure out whether the new stack > is above or below the single known good address, and then scale back > either the tos or the bos accordingly. > > Signed-off-by: Mike Frysinger <[email protected]> > --- > libpthread/linuxthreads.old/internals.h | 16 ++++++++++++---- > libpthread/linuxthreads.old/pthread.c | 13 ++++++++----- > 2 files changed, 20 insertions(+), 9 deletions(-) > > diff --git a/libpthread/linuxthreads.old/internals.h > b/libpthread/linuxthreads.old/internals.h > index 637fcea..2999baf 100644 > --- a/libpthread/linuxthreads.old/internals.h > +++ b/libpthread/linuxthreads.old/internals.h > @@ -258,11 +258,19 @@ extern pthread_descr __pthread_main_thread; > > extern char *__pthread_initial_thread_bos; > #ifndef __ARCH_USE_MMU__ > -extern char *__pthread_initial_thread_tos; > +extern char *__pthread_initial_thread_tos, *__pthread_initial_thread_mid; A comment here describing the _mid logic would be helpful down the road - maybe something that paraphrases the last paragraph of your changelog. > #define NOMMU_INITIAL_THREAD_BOUNDS(tos,bos) \ > - if ((tos)>=__pthread_initial_thread_bos \ > - && (bos)<__pthread_initial_thread_tos) \ > - __pthread_initial_thread_bos = (tos)+1 > + do { \ > + char *__tos = (tos); \ > + char *__bos = (bos); \ > + if (__tos >= __pthread_initial_thread_bos && \ > + __bos < __pthread_initial_thread_tos) { \ > + if (__bos < __pthread_initial_thread_mid) \ > + __pthread_initial_thread_bos = __tos; \ > + else \ > + __pthread_initial_thread_tos = __bos; \ > + } \ > + } while (0) > #else > #define NOMMU_INITIAL_THREAD_BOUNDS(tos,bos) /* empty */ > #endif /* __ARCH_USE_MMU__ */ > diff --git a/libpthread/linuxthreads.old/pthread.c > b/libpthread/linuxthreads.old/pthread.c > index ad392e3..3878984 100644 > --- a/libpthread/linuxthreads.old/pthread.c > +++ b/libpthread/linuxthreads.old/pthread.c > @@ -174,6 +174,7 @@ char *__pthread_initial_thread_bos = NULL; > > #ifndef __ARCH_USE_MMU__ > char *__pthread_initial_thread_tos = NULL; > +char *__pthread_initial_thread_mid = NULL; > #endif /* __ARCH_USE_MMU__ */ > > /* File descriptor for sending requests to the thread manager. */ > @@ -457,12 +458,14 @@ static void pthread_initialize(void) > setrlimit(RLIMIT_STACK, &limit); > } > #else > - /* For non-MMU assume __pthread_initial_thread_tos at upper page boundary, > and > - * __pthread_initial_thread_bos at address 0. These bounds are refined as > we > - * malloc other stack frames such that they don't overlap. -StS > + /* For non-MMU we need to start the initial thread stack for all available > + * memory. These bounds are refined as we malloc other stack frames such > + * that they don't overlap. We cannot pick an arbitrary tos point (such as > + * rounding up a page) as it might be slightly crossing page boundaries in > + * the middle of this code execution. > */ How about: /* For non-MMU, the initial thread stack can reside anywhere in memory. * All we can determine here is an address that lies within that stack. * Save that address as a reference so that as other thread stacks are * created, we can adjust the estimated bounds of the initial thread's * stack appropriately. */ > - __pthread_initial_thread_tos = > - (char *)(((long)CURRENT_STACK_FRAME + getpagesize()) & ~(getpagesize() - > 1)); > + __pthread_initial_thread_mid = (long)CURRENT_STACK_FRAME; > + __pthread_initial_thread_tos = (char *) -1; > __pthread_initial_thread_bos = (char *) 1; /* set it non-zero so we know > we have been here */ > PDEBUG("initial thread stack bounds: bos=%p, tos=%p\n", > __pthread_initial_thread_bos, __pthread_initial_thread_tos); > -- > 1.7.4.1 ------------------------------------------------------------------------ Steven J. Magnani "I claim this network for MARS! www.digidescorp.com Earthling, return my space modulator!" #include <standard.disclaimer> _______________________________________________ uClibc mailing list [email protected] http://lists.busybox.net/mailman/listinfo/uclibc
