Re: dlopen() and dlclose() are not MT-safe?



On Wed, Mar 22, 2006 at 07:43:12PM +0200, Kostik Belousov wrote:
On Wed, Mar 22, 2006 at 11:32:09PM +0900, Kazuaki Oda wrote:
Hello,

I compiled the following code on 6.1-PRERELEASE and ran:

dltest.c
----------------------------------------------------------------------
#include <err.h>
#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define NTHREADS 10

void *func(void *dummy);

int main(void)
{
pthread_t tids[NTHREADS];
int error;
int i;

for (i = 0; i < NTHREADS; i++) {
error = pthread_create(&tids[i], NULL, func, NULL);
if (error)
errc(1, error, "pthread_create");
}

for (;;)
sleep(1);

/* NOTREACHED */

exit(0);
}

void *func(void *dummy)
{
void *h;

for (;;) {
if ((h = dlopen("/usr/lib/libm.so", RTLD_NOW)) == NULL)
errx(1, "dlopen: %s", dlerror());
if (dlclose(h) == -1)
errx(1, "dlclose: %s", dlerror());
}

/* NOTREACHED */

return (NULL);
}
----------------------------------------------------------------------

% cc -Wall -o dltest dltest.c -lpthread
% ./dltest
ld-elf.so.1: assert failed: /usr/src/libexec/rtld-elf/rtld.c:2445
Segmentation fault (core dumped)

% cc -Wall -o dltest dltest.c -lthr
% ./dltest
% ld-elf.so.1: assert failed: /usr/src/libexec/rtld-elf/rtld.c:1723
Abort (core dumped)

Hmm, it seems dlopen() and dlclose() are not MT-safe. Is this a known
issue?

--
Kazuaki Oda

The following patch put some relief for the problem:

Index: libexec/rtld-elf/rtld.c ===================================================================
RCS file: /usr/local/arch/ncvs/src/libexec/rtld-elf/rtld.c,v
retrieving revision 1.112
diff -u -r1.112 rtld.c
--- libexec/rtld-elf/rtld.c 24 Dec 2005 15:37:30 -0000 1.112
+++ libexec/rtld-elf/rtld.c 22 Mar 2006 17:33:06 -0000
@@ -1688,6 +1688,12 @@
wlock_release(rtld_bind_lock, lockstate);
objlist_call_fini(&list_fini);
lockstate = wlock_acquire(rtld_bind_lock);
+ if (root->refcount == 0) {
+ _rtld_error("%s: object busy", root->path);
+ wlock_release(rtld_bind_lock, lockstate);
+ return -1;
+ }
+
objlist_remove_unref(&list_fini);

/* Finish cleaning up the newly-unreferenced objects. */


But it still allows for the mess of _init/_fini simultaneous calls
from different threads. SUSv3 does not mention constructors/destructors.

Oops. Completely reversed condition in the if. :(. Also, I don't think it
shall returns the error in this situation. New take:

Index: libexec/rtld-elf/rtld.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/libexec/rtld-elf/rtld.c,v
retrieving revision 1.112
diff -u -r1.112 rtld.c
--- libexec/rtld-elf/rtld.c 24 Dec 2005 15:37:30 -0000 1.112
+++ libexec/rtld-elf/rtld.c 22 Mar 2006 19:03:12 -0000
@@ -1688,6 +1688,11 @@
wlock_release(rtld_bind_lock, lockstate);
objlist_call_fini(&list_fini);
lockstate = wlock_acquire(rtld_bind_lock);
+ if (root->refcount != 0) {
+ wlock_release(rtld_bind_lock, lockstate);
+ return 0;
+ }
+
objlist_remove_unref(&list_fini);

/* Finish cleaning up the newly-unreferenced objects. */

Attachment: pgph2BZGDsADg.pgp
Description: PGP signature



Relevant Pages

  • Re: Whats the point of __KERNEL_SYSCALLS__?
    ... retrieving revision 1.4 ... diff -u -p -r1.4 process.c ... -static int errno; ... * calls - which means inline code for fork too, ...
    (Linux-Kernel)
  • [RFC][PATCH] i386: Per node IDT
    ... retrieving revision 1.1.1.1 ... +int assign_irq_vector ... +static inline void ioapic_register_intr(int node, int irq, int vector, unsigned long trigger) ...
    (Linux-Kernel)
  • Re: Sequence of packet processing with ipfw, pf, ipfilter ?
    ... retrieving revision 1.21 ... diff -u -r1.93.2.1 bridge.c ... -static __inline int ... pfil_run_hooksruns the specified packet filter hooks. ...
    (freebsd-stable)
  • Linux compatible setaffinity.
    ... int sched_setaffinity; ... diff -u -r1.2.10.2 kern_resource.c ... retrieving revision 1.1 ... Please copy any additions and changes to the following compatability tables: ...
    (freebsd-arch)
  • RE: [RFC][2.6.12.3] IRQ compression/sharing patch
    ... retrieving revision 1.1.1.1 ... +int assign_irq_vector ... +static inline void ioapic_register_intr(int node, int irq, int vector, unsigned long trigger) ...
    (Linux-Kernel)