Date: Sat, 20 Aug 2005 16:32:39 GMT From: Pascal Hofstee <caelian@gmail.com> To: freebsd-gnats-submit@FreeBSD.org Subject: threads/85160: libobjc + libpthread/libthr crash problem Message-ID: <200508201632.j7KGWd9B026955@www.freebsd.org> Resent-Message-ID: <200508201640.j7KGeGd8006209@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 85160 >Category: threads >Synopsis: libobjc + libpthread/libthr crash problem >Confidential: no >Severity: critical >Priority: low >Responsible: freebsd-threads >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sat Aug 20 16:40:16 GMT 2005 >Closed-Date: >Last-Modified: >Originator: Pascal Hofstee >Release: FreeBSD 7.0-CURRENT amd64 >Organization: >Environment: System: FreeBSD 7.0-CURRENT #7: Wed Aug 17 22:27:49 PDT 2005 daeron@synergy.charterpipeline.net.lan:/usr/obj/usr/src/sys/SYNERGY >Description: Ever since the GNUstep project decided to make certain changes regarding how GNUstep applications should be linked to external libraries ... GNUstep builds on the FreeBSD platform appeared to be broken where they used to function properly before. (Problem being applications segfaulting in libobjc's thread initialization) A while ago now, David Ayers, one of the people with an active GNUstep interest and willingness to see this issue resolved was kind enough to allow me to provide him access to my FreeBSD/amd64 7.0-CURRENT machine in an attempt to get to the bottom of this issue. His final analysis boils down to the following: ----[ Analysis of GNUstep on FreeBSD pthread problem ]---- The real bug does indeed lie in the internal initialization process of the FreeBSD libpthread library. In this case when libobjc is not excplitly linked into the executable, (and is further at the bottom of the ldd depenency list) it get's initialized before libpthread does. i.e. it starts calling libpthread functions before the following constructor: void _thread_init_hack(void) __attribute__ ((constructor)); void _thread_init_hack(void) { _libpthread_init(NULL); } of the libpthread library is called. This constructor sets up the data structures for _get_curthread(). The function that libobjc calls early: pthread_key_create() calls _get_currthread which still returns NULL. This pointer is then dereferenced in the THR_LOCK_ACQUIRE macro resulting in the segfault. Many of the mutex functions have already been guarded for this case with the following code fragements: if (_thr_initial == NULL) _libpthread_init(NULL); See also the following comment in thr_create.c: .. * Some notes on new thread creation and first time initializion * to enable multi-threading. * * There are basically two things that need to be done. * * 1) The internal library variables must be initialized. * 2) Upcalls need to be enabled to allow multiple threads * to be run. * * The first may be done as a result of other pthread functions * being called. When _thr_initial is null, _libpthread_init is * called to initialize the internal variables; this also creates * or sets the initial thread. It'd be nice to automatically * have _libpthread_init called on program execution so we don't * have to have checks throughout the library. .. So they seem to be aware of the issue but haven't guarded all functions like pthread_key_create() which libobjc calls. I don't believe that we can find a reliable workaround within GNUstep. I also don't know if this bug is in a stable release version of FreeBSD. But I want to mention that a call to pthread_self() would workaround this. Yet this call would have to be done in libobjc's __objc_init_thread_system and not in GNUstep. The other hack is to fiddle with the link order so that the constructor above can cover up the issue. I'll leave it up to the -make maintainers to decide what to do. My current tendency is to close this bug as invalid at least until someone verifies that the issue exists with released versions of FreeBSD. And even then a workaround should probably be done in libobjc (which seems to be installed by FreeBSD but if libobjc needs updating you might as well update libpthread instead and fix the bug properly). ----[ End of Analysis]---- On a sidenote .. this same problem is duplicated when using libthr ... and does not occur when using libc_r. the proposed fixes seem to cause no ill-effects (i've been running with them locally for a full month by now ... if a similar fix could be applied inside _get_curthread() that would like be the most ideal situation .. but i would rather have somebody confirm such a solution would indeed be possible there. >How-To-Repeat: The problem manifests itself when an application linked against libpthread/libthr indirectly links in libobjc. During application startup .. libobjc apparently gets to run its initialization routines before libpthread gets a chance to execute its _thread_init_hack constructor .. causing NULL pointer dereferences in pthread_key_create() >Fix: --- libthr.diff begins here --- --- lib/libthr/thread/thr_spec.c.orig Sat Jul 16 19:29:04 2005 +++ lib/libthr/thread/thr_spec.c Sat Jul 16 19:29:14 2005 @@ -52,8 +52,13 @@ int _pthread_key_create(pthread_key_t *key, void (*destructor) (void *)) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; int i; + + if (_thr_initial == NULL) + _libpthread_init(NULL); + + curthread = _get_curthread(); /* Lock the key table: */ THR_LOCK_ACQUIRE(curthread, &_keytable_lock); --- libthr.diff ends here --- --- libpthread.diff begins here --- --- lib/libpthread/thread/thr_spec.c.orig Sat Jul 16 19:28:31 2005 +++ lib/libpthread/thread/thr_spec.c Sat Jul 16 19:28:41 2005 @@ -50,8 +50,13 @@ int _pthread_key_create(pthread_key_t *key, void (*destructor) (void *)) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; int i; + + if (_thr_initial == NULL) + _libpthread_init(NULL); + + curthread = _get_curthread(); /* Lock the key table: */ THR_LOCK_ACQUIRE(curthread, &_keytable_lock); --- libpthread.diff ends here --- >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200508201632.j7KGWd9B026955>