Date: Wed, 22 Mar 2006 21:07:25 +0200 From: Kostik Belousov <kostikbel@gmail.com> To: Kostik Belousov <kostikbel@gmail.com> Cc: hackers@freebsd.org, kan@freebsd.org, Kazuaki Oda <kaakun@highway.ne.jp> Subject: Re: dlopen() and dlclose() are not MT-safe? Message-ID: <20060322190725.GC27116@deviant.kiev.zoral.com.ua> In-Reply-To: <20060322174312.GB27116@deviant.kiev.zoral.com.ua> References: <44215FE9.2070602@highway.ne.jp> <20060322174312.GB27116@deviant.kiev.zoral.com.ua>
next in thread | previous in thread | raw e-mail | index | archive | help
--bCsyhTFzCvuiizWE
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
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,
> >=20
> > I compiled the following code on 6.1-PRERELEASE and ran:
> >=20
> > dltest.c
> > ----------------------------------------------------------------------
> > #include <err.h>
> > #include <dlfcn.h>
> > #include <pthread.h>
> > #include <stdio.h>
> > #include <stdlib.h>
> > #include <unistd.h>
> >=20
> > #define NTHREADS 10
> >=20
> > void *func(void *dummy);
> >=20
> > int main(void)
> > {
> > pthread_t tids[NTHREADS];
> > int error;
> > int i;
> >=20
> > for (i =3D 0; i < NTHREADS; i++) {
> > error =3D pthread_create(&tids[i], NULL, func, NULL);
> > if (error)
> > errc(1, error, "pthread_create");
> > }
> >=20
> > for (;;)
> > sleep(1);
> >=20
> > /* NOTREACHED */
> >=20
> > exit(0);
> > }
> >=20
> > void *func(void *dummy)
> > {
> > void *h;
> >=20
> > for (;;) {
> > if ((h =3D dlopen("/usr/lib/libm.so", RTLD_NOW)) =3D=3D NULL)
> > errx(1, "dlopen: %s", dlerror());
> > if (dlclose(h) =3D=3D -1)
> > errx(1, "dlclose: %s", dlerror());
> > }
> >=20
> > /* NOTREACHED */
> >=20
> > return (NULL);
> > }
> > ----------------------------------------------------------------------
> >=20
> > % 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)
> >=20
> > % 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)
> >=20
> > Hmm, it seems dlopen() and dlclose() are not MT-safe. Is this a known
> > issue?
> >=20
> > --
> > Kazuaki Oda
>=20
> The following patch put some relief for the problem:
>=20
> Index: libexec/rtld-elf/rtld.c =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> 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 =3D wlock_acquire(rtld_bind_lock);
> + if (root->refcount =3D=3D 0) {
> + _rtld_error("%s: object busy", root->path);
> + wlock_release(rtld_bind_lock, lockstate);
> + return -1;
> + }
> +
> objlist_remove_unref(&list_fini);
>=20
> /* Finish cleaning up the newly-unreferenced objects. */
>=20
>=20
> 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
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
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 =3D wlock_acquire(rtld_bind_lock);
+ if (root->refcount !=3D 0) {
+ wlock_release(rtld_bind_lock, lockstate);
+ return 0;
+ }
+
objlist_remove_unref(&list_fini);
/* Finish cleaning up the newly-unreferenced objects. */
--bCsyhTFzCvuiizWE
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (FreeBSD)
iD8DBQFEIaBsC3+MBN1Mb4gRAr1rAJoDR1ZQ3n0+XBy06Xa9jUHVVVueEwCfdj7a
jRmZF2qC7Tj88xUXv1Y4II4=
=WfEu
-----END PGP SIGNATURE-----
--bCsyhTFzCvuiizWE--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20060322190725.GC27116>
