misc/151861: dlclose() of library causes separately opened
libraries to unload as well
Kostik Belousov
kostikbel at gmail.com
Wed Nov 3 11:00:23 UTC 2010
The following reply was made to PR misc/151861; it has been noted by GNATS.
From: Kostik Belousov <kostikbel at gmail.com>
To: Jaakko Heinonen <jh at freebsd.org>
Cc: Arjan van Leeuwen <freebsd-maintainer at opera.com>, bug-followup at freebsd.org,
kan at freebsd.org
Subject: Re: misc/151861: dlclose() of library causes separately opened libraries to unload as well
Date: Wed, 3 Nov 2010 12:54:29 +0200
--b2N6ngaUR9vV44n2
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
On Wed, Nov 03, 2010 at 12:06:49PM +0200, Jaakko Heinonen wrote:
> On 2010-11-02, Kostik Belousov wrote:
> > Why do you think that your patch is not correct ?
>=20
> Well, I didn't say that I think it's incorrect. :)
>=20
> > I feel that more explicit handling of the state of the DAG is cleaner.
>=20
> I don't disagree but there is a problem with your patch. If an object
> has the DF_1_NODELETE flag set, dag is initialized in
> load_needed_objects(). In this case the reference count isn't correctly
> bumped in dlopen() because dag_inited is already set.
Seems you are right. See that patch below.
It changes init_dag() to unconditionally increment refcount.
>=20
> (BTW. I think that there shouldn't be the ref_dag(obj1) call in
> load_needed_objects(). Now the reference count is increased twice in the
> nodelete case.)
With init_dag() incrementing the refcount unconditionally, the ref_dag()
indeed can be removed.
>=20
> > --- a/libexec/rtld-elf/rtld.c
> > +++ b/libexec/rtld-elf/rtld.c
> > @@ -1275,8 +1275,11 @@ init_dag(Obj_Entry *root)
> > {
> > DoneList donelist;
> > =20
> > + if (root->dag_inited)
> > + return;
>=20
> Why init_dag() should be allowed to be called multiple times for an
> object?
If already loaded object is dlopened, dlclosed, and then again dlopened,
init_dag() will be called twice, one time for each dlopen.
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index f1ffc3e..f75ee35 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -1275,11 +1275,12 @@ init_dag(Obj_Entry *root)
{
DoneList donelist;
=20
- if (root->dag_inited)
- return;
- donelist_init(&donelist);
- init_dag1(root, root, &donelist);
- root->dag_inited =3D true;
+ if (!root->dag_inited) {
+ donelist_init(&donelist);
+ init_dag1(root, root, &donelist);
+ root->dag_inited =3D true;
+ }
+ ref_dag(root);
}
=20
static void
@@ -1290,7 +1291,6 @@ init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *=
dlp)
if (donelist_check(dlp, obj))
return;
=20
- obj->refcount++;
objlist_push_tail(&obj->dldags, root);
objlist_push_tail(&root->dagmembers, obj);
for (needed =3D obj->needed; needed !=3D NULL; needed =3D needed->ne=
xt)
@@ -1438,7 +1438,6 @@ load_needed_objects(Obj_Entry *first, int flags)
if (obj1 !=3D NULL && obj1->z_nodelete && !obj1->ref_nodel) {
dbg("obj %s nodelete", obj1->path);
init_dag(obj1);
- ref_dag(obj1);
obj1->ref_nodel =3D true;
}
}
@@ -2054,10 +2053,7 @@ dlopen(const char *name, int mode)
* already loaded as a dependency, initialize the dag
* starting at it.
*/
- if (obj->dl_refcount =3D=3D 1)
- init_dag(obj);
- else
- ref_dag(obj);
+ init_dag(obj);
=20
if (ld_tracing)
goto trace;
--b2N6ngaUR9vV44n2
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (FreeBSD)
iEYEARECAAYFAkzRP2QACgkQC3+MBN1Mb4hlxQCfVo6OyCtfOu/iMiG444ql0rP8
dT4An2sqpVM/mqJbwYnw2vJoopDqvqqC
=rUZc
-----END PGP SIGNATURE-----
--b2N6ngaUR9vV44n2--
More information about the freebsd-bugs
mailing list