diff --git a/ldso/dynlink.c b/ldso/dynlink.c index a03f75e..3e52beb 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; @@ -934,6 +935,7 @@ static struct dso *load_library(const char *name, struct dso *needed_by) if (!ldso.prev) { tail->next = &ldso; ldso.prev = tail; + ldso.needed_by = needed_by; tail = ldso.next ? ldso.next : &ldso; } return &ldso; @@ -1090,9 +1092,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; @@ -1110,7 +1115,7 @@ static void load_preload(char *s) for (z=s; *z && !isspace(*z) && *z!=':'; z++); tmp = *z; *z = 0; - load_library(s, 0); + load_library(s, head); *z = tmp; } } @@ -1211,13 +1216,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) { - do_init_fini(tail); + do_init_fini(head); } static void dl_debug_state(void) @@ -1731,7 +1746,7 @@ end: __release_ptc(); if (p) gencnt++; pthread_rwlock_unlock(&lock); - if (p) do_init_fini(orig_tail); + if (p) do_init_fini(p); pthread_setcancelstate(cs, 0); return p; }