[PATCH] ldso: fix dlsym hang when reloading DSOs

Bernhard Reutner-Fischer rep.dot.nop at gmail.com
Thu Jun 27 19:25:12 UTC 2013


On 27 June 2013 21:07:38 Timo Teras <timo.teras at iki.fi> wrote:
> On Thu, 27 Jun 2013 20:36:44 +0200
> "Bernhard Reutner-Fischer" <rep.dot.nop at gmail.com> wrote:
>
> > On 27 June 2013 20:16:26 Rich Felker <dalias at aerifal.cx> wrote:
> > > On Thu, Jun 27, 2013 at 09:34:32AM +0300, Timo Teräs wrote:
> > > > It can happen under certain cases that the DSO had refcount 0,
> > > > but was already loaded. (NODELETE flag is set, or it is pulled
> > > > in via both NEEDED dependency and explicit dlopen()).
> > >
> > > Wouldn't it be more logical to prevent this from happening by not
> > > using a refcount of zero? For example, NODELETE could just perform
> > > an extra increment on the refcnt so that it never reaches 0. In
> > > essence, the NODELETE flag is a permanent reference to the DSO.
> > I was thinking the same, without having looked yet. This does not
> > sound like the correct fix.
>
> This would be the alternate patch - but somehow I lost my original test
> case. And qemu seems to now depend on GTK making the other known issue
> also go away.
>
> Paolo, could you test if this fixes your problem also?
>
> diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
> index 96459f3..71133dd 100644
> --- a/ldso/ldso/dl-elf.c
> +++ b/ldso/ldso/dl-elf.c
> @@ -831,6 +831,8 @@ struct elf_resolve 
> *_dl_load_elf_shared_library(unsigned rflags,
>  #endif
>  	(*rpnt)->dyn = tpnt;
>  	tpnt->usage_count++;
> +	if (rtld_flags & RTLD_NODELETE)
> +		tpnt->usage_count++;
>  #ifdef __LDSO_STANDALONE_SUPPORT__
>  	tpnt->libtype = (epnt->e_type == ET_DYN) ? elf_lib : elf_executable;
>  #else
> diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
> index c451b63..035b56d 100644
> --- a/ldso/libdl/libdl.c
> +++ b/ldso/libdl/libdl.c
> @@ -822,7 +822,7 @@ static int do_dlclose(void *vhandle, int need_fini)
>  		_dl_handles = rpnt->next_handle;
>  	_dl_if_debug_print("%s: usage count: %d\n",
>  			handle->dyn->libname, handle->dyn->usage_count);
> -	if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & 
> RTLD_NODELETE)) {
> +	if (handle->dyn->usage_count != 1) {
>  		handle->dyn->usage_count--;
>  		free(handle);
>  		return 0;
> @@ -844,7 +844,7 @@ static int do_dlclose(void *vhandle, int need_fini)
>  	for (j = 0; j < handle->init_fini.nlist; ++j) {
>  		tpnt = handle->init_fini.init_fini[j];
>  		tpnt->usage_count--;

We want to keep usage_count at at least 1 if NODELETE here in dlclose:
tpnt->usage_count -= !(tpnt->rtld_flags & RTLD_NODELETE);
Instead, or, better -- and then
usage_count = MAX(usage_count, usage_count & RTLD_NODELETE);
or something to that effect.

Thanks,
> -		if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
> +		if (tpnt->usage_count == 0) {
>  			if ((tpnt->dynamic_info[DT_FINI]
>  			     || tpnt->dynamic_info[DT_FINI_ARRAY])
>  			 && need_fini


Sent with AquaMail for Android
http://www.aqua-mail.com




More information about the uClibc mailing list