Here goes another portability issue I've met multiple times while packaging software for NetBSD 2.x, where libpthread has some restrictions that other systems don't seem to have. Simply put, a non-threaded program cannot become threaded at run time, because, if it does, you get a nice "Abort trap". But, how can this happen?

Suppose you have an application that is not linked against libpthread, neither directly nor indirectly (through required libraries). The initialization code used to set up this program doesn't need to care about threads, because it's assumed that they won't be used. Hence you have a non-threaded program. Note that the important part here is the initialization code used to setup the program, not whether the program uses calls to pthread_* functions or not.

Now imagine that this non-thread program loads a shared object (be it a library or a plugin) using dlopen(3). This is not by itself a problem. The funny part comes when the shared object being opened is linked against libpthread; that is, threaded code. There you have the "Abort trap". You have loaded threaded code into a non-threaded application. Here is a little example for you to play with:

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

int
main(void)
{
void *handle;

(void)printf("Loading libpthread.son");
handle = dlopen("libpthread.so", RTLD_LAZY);
(void)printf("libpthread.so loadedn");
dlclose(handle);

return EXIT_SUCCESS;
}

Can this problem be worked around? Sure. It's as simple as linking the non-threaded application against libpthread (even if it won't make any use of threads), because this library will override the initialization code used to set up the program. I've done this, for example, in the gtk-query-immodules-2.0 utility that comes with GTK+, because some plugins loaded by it are threaded.

Considering the previous example, doing: cc test.c ; ./a.out will produce a crash. But cc -lpthread test.c ; ./a.out will not. And even cc test.c ; LD_PRELOAD=/usr/lib/libpthread.so ./a.out will work too. Remember? It's the initialization code that matters, not the amount of threads used by the code.

Now, before thinking this is a bug in NetBSD, let me say that this was a design decision in the libpthread library. I don't remember the rationale behind it, but I guess you should be able to find it Googleing a bit ;-)