bug-glibc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: pthread in glibc2.2.2


From: Dan Maas
Subject: Re: pthread in glibc2.2.2
Date: Mon, 2 Apr 2001 02:41:32 -0400

> > Maintainers, has any decision been made about a proper fix? Either glibc
or
> > gcc needs to be modified in order for LDT-based linuxthreads to work...
>
> *Nothing* I've seen suggests that there is anything wrong.  Provide me
> a small and self-contained example.  Otherwise noting will ever
> happen.  In almost all cases it simply an user error.

Glibc 2.2.2 and linuxthreads *compiled with LDT enabled* cause any program
that is linked to libpthread.so to SEGV immediately on startup. Here is a
complete explanation...

The old non-LDT method of managing thread-specific data did not require any
initialization before use (pthreads would get a thread-specific pointer by
looking at where the stack lies in memory).

LDT adds a new requirement that pthreads must perform some intialization
before it can service pthread calls. Specifically, it has to make a
'modify_ldt' system call, and set the 'gs' register (see
glibc-2.2.2/linuxthreads/sysdeps/i386/useldt.h). If this initialization has
not been performed, and you try to call, for example, pthread_mutex_lock(),
pthreads will dereference the uninitialized 'gs' register, causing a
segfault.

When you compile pthreads with LDT, it adds a call to the proper LDT
initialization function in _init(), which the shared library loader is
supposed to call immediately after loading libpthread.so.

*however*...

In order to support C++ exceptions, programs compiled with GCC maintain a
global table of stack frame layouts. GCC transparently inserts a function
called __register_frame_info() into all executables and shared libraries it
compiles. __register_frame_info() is supposed to be called when the
executable starts running, and also when any shared library is loaded -- its
job is to add the stack frame information from that piece of code into the
global table. Since the stack frame table is global, it needs to be
protected by a mutex (otherwise two libraries loading at the same time could
corrupt it). Therefore, GCC invisibly inserts calls to pthread_mutex_lock()
inside __register_frame_info(). This never caused a problem before, because
non-LDT pthreads required no initialization.

But, there is sort of a chicken-and-egg problem now... libc.so is always
loaded before libpthread.so. That means libc makes its call to
__register_frame_info() *before* the pthreads _init() function gets a chance
to run. So when __register_frame_info() tries to lock the stack frame mutex,
it segfaults (it dereferences the not-yet-initialized 'gs' register).

The solution is to make sure that pthreads gets a chance to initialize
before any of the __register_frame_info() functions are called. Glibc
previously contained a little hack to accomplish this, but for some reason
it was removed in the 2.2.2 release. Here is the CVS commit that breaks
LDT pthreads (careful of the line break):

http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/elf/soinit.c.diff?r1=1.8&r
2=1.9&cvsroot=glibc&f=h

So that brings us to today - LDT-based pthreads does not work because
it is not initialized before __register_frame_info().

Regards,
Dan




reply via email to

[Prev in Thread] Current Thread [Next in Thread]