diff --git a/ldso/dynlink.c b/ldso/dynlink.c index c689084..fd59389 100644 --- a/ldso/dynlink.c +++ b/ldso/dynlink.c @@ -67,6 +67,7 @@ struct dso { char constructed; char kernel_mapped; struct dso **deps, *needed_by; + size_t next_dep; char *rpath_orig, *rpath; struct tls_module tls; size_t tls_id; @@ -1090,9 +1091,12 @@ static void load_deps(struct dso *p) if (runtime) longjmp(*rtld_fail, 1); continue; } - if (runtime) { - tmp = realloc(*deps, sizeof(*tmp)*(ndeps+2)); - if (!tmp) longjmp(*rtld_fail, 1); + tmp = realloc(*deps, sizeof(*tmp)*(ndeps+2)); + if (!tmp) { + error("Error allocating dependency data for %s: %m", + p->name); + if (runtime) longjmp(*rtld_fail, 1); + } else { tmp[ndeps++] = dep; tmp[ndeps] = 0; *deps = tmp; @@ -1211,13 +1215,21 @@ void __libc_exit_fini() static void do_init_fini(struct dso *p) { size_t dyn[DYN_CNT]; - int need_locking = libc.threads_minus_1; - /* Allow recursive calls that arise when a library calls - * dlopen from one of its constructors, but block any - * other threads until all ctors have finished. */ - if (need_locking) pthread_mutex_lock(&init_fini_lock); - for (; p; p=p->prev) { - if (p->constructed) continue; + pthread_mutex_lock(&init_fini_lock); + /* Construct in dependency order without any recursive state. */ + while (p && !p->constructed) { + /* The following loop descends into the first dependency + * that is neither alredy constructed nor pending + * construction due to circular deps, stopping only + * when it reaches a dso with no remaining dependencies + * to descend into. */ + while (p->deps && p->deps[p->next_dep]) { + if (!p->deps[p->next_dep]->constructed && + !p->deps[p->next_dep]->next_dep) + p = p->deps[p->next_dep++]; + else + p->next_dep++; + } p->constructed = 1; decode_vec(p->dynv, dyn, DYN_CNT); if (dyn[0] & ((1<needed_by; + } + pthread_mutex_unlock(&init_fini_lock); } void __libc_start_init(void)