summaryrefslogtreecommitdiff
path: root/elf/dl-open.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-open.c')
-rw-r--r--elf/dl-open.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/elf/dl-open.c b/elf/dl-open.c
index df9f29a5e5..9819b49e4f 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -35,6 +35,7 @@
#include <libc-internal.h>
#include <array_length.h>
#include <internal-signals.h>
+#include <libc-early-init.h>
#include <dl-dst.h>
#include <dl-prop.h>
@@ -53,6 +54,13 @@ struct dl_open_args
/* Namespace ID. */
Lmid_t nsid;
+ /* Set to true if libc.so was already loaded into the namespace at
+ the time dl_open_worker was called. This is used to determine
+ whether libc.so early initialization needs to before, and whether
+ to roll back the cached libc_map value in the namespace in case
+ of a dlopen failure. */
+ bool libc_already_loaded;
+
/* Original signal mask. Used for unblocking signal handlers before
running ELF constructors. */
sigset_t original_signal_mask;
@@ -511,6 +519,11 @@ dl_open_worker (void *a)
args->nsid = call_map->l_ns;
}
+ /* The namespace ID is now known. Keep track of whether libc.so was
+ already loaded, to determine whether it is necessary to call the
+ early initialization routine (or clear libc_map on error). */
+ args->libc_already_loaded = GL(dl_ns)[args->nsid].libc_map != NULL;
+
/* Retain the old value, so that it can be restored. */
args->original_global_scope_pending_adds
= GL (dl_ns)[args->nsid]._ns_global_scope_pending_adds;
@@ -745,6 +758,11 @@ dl_open_worker (void *a)
if (relocation_in_progress)
LIBC_PROBE (reloc_complete, 3, args->nsid, r, new);
+ /* If libc.so was not there before, attempt to call its early
+ initialization routine. */
+ if (!args->libc_already_loaded)
+ _dl_call_libc_early_init (GL(dl_ns)[args->nsid].libc_map);
+
#ifndef SHARED
DL_STATIC_INIT (new);
#endif
@@ -843,6 +861,7 @@ no more namespaces available for dlmopen()"));
args.caller_dlopen = caller_dlopen;
args.map = NULL;
args.nsid = nsid;
+ args.libc_already_loaded = true; /* No reset below with early failure. */
args.argc = argc;
args.argv = argv;
args.env = env;
@@ -875,6 +894,11 @@ no more namespaces available for dlmopen()"));
/* See if an error occurred during loading. */
if (__glibc_unlikely (exception.errstring != NULL))
{
+ /* Avoid keeping around a dangling reference to the libc.so link
+ map in case it has been cached in libc_map. */
+ if (!args.libc_already_loaded)
+ GL(dl_ns)[nsid].libc_map = NULL;
+
/* Remove the object from memory. It may be in an inconsistent
state if relocation failed, for example. */
if (args.map)