GNUstep, libobjc and threading

Pascal Hofstee caelian at
Fri Jul 15 19:07:35 GMT 2005


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)

During the last couple of days, 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

void _thread_init_hack(void) __attribute__ ((constructor)); 



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) 

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 (likely similarly) when
using libthr ... and does not occur when using libc_r.

Is the above analysis enough information to hopefully fix this problem
with FreeBSD's threading libraries ... and would properly gaurding the
mentioned pthread_key_create function with a similar _thread_initial
check be sufficient ?

With kind regards, and hoping to get some feedback on this ...
  Pascal Hofstee

More information about the freebsd-threads mailing list