2000-12-30  Ulrich Drepper  <drepper@redhat.com>

	* elf/dl-close.c (_dl_close): We can ignore the NODELETE flag if the
	object was not yet initialized.

2000-12-28  H.J. Lu  <hjl@gnu.org>

	* elf/dl-deps.c (_dl_map_object_deps): Make sure the DSO state
	is always consistent even if its dependency is failed.

	* elf/dl-open.c (_dl_open): Increment the open count before
	calling _dl_close () in case of failure.

	* elf/neededtest4.c: New file.
	* elf/neededobj5.c: New file.
	* elf/neededobj6.c: New file.

	* elf/Makefile (distribute): Add neededobj5.c and neededobj6.c.
	(tests): Add neededtest4.
	(modules-names): Add neededobj5 and neededobj6.
	($(objpfx)neededobj6.so): New target.
	($(objpfx)neededtest4): New target.
	($(objpfx)neededtest4.out): New target.
This commit is contained in:
Ulrich Drepper 2000-12-31 06:09:08 +00:00
parent d9af88677f
commit c77a447822
8 changed files with 256 additions and 20 deletions

View File

@ -1,3 +1,27 @@
2000-12-30 Ulrich Drepper <drepper@redhat.com>
* elf/dl-close.c (_dl_close): We can ignore the NODELETE flag if the
object was not yet initialized.
2000-12-28 H.J. Lu <hjl@gnu.org>
* elf/dl-deps.c (_dl_map_object_deps): Make sure the DSO state
is always consistent even if its dependency is failed.
* elf/dl-open.c (_dl_open): Increment the open count before
calling _dl_close () in case of failure.
* elf/neededtest4.c: New file.
* elf/neededobj5.c: New file.
* elf/neededobj6.c: New file.
* elf/Makefile (distribute): Add neededobj5.c and neededobj6.c.
(tests): Add neededtest4.
(modules-names): Add neededobj5 and neededobj6.
($(objpfx)neededobj6.so): New target.
($(objpfx)neededtest4): New target.
($(objpfx)neededtest4.out): New target.
2000-12-28 Joseph S. Myers <jsm28@cam.ac.uk> 2000-12-28 Joseph S. Myers <jsm28@cam.ac.uk>
* misc/sys/cdefs.h (__attribute_format_strfmon__): Define. * misc/sys/cdefs.h (__attribute_format_strfmon__): Define.

View File

@ -55,6 +55,7 @@ distribute := $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
reldepmod1.c reldepmod2.c reldepmod3.c reldepmod4.c \ reldepmod1.c reldepmod2.c reldepmod3.c reldepmod4.c \
nextmod1.c nextmod2.c pathoptobj.c tst-pathopt.sh \ nextmod1.c nextmod2.c pathoptobj.c tst-pathopt.sh \
neededobj1.c neededobj2.c neededobj3.c neededobj4.c \ neededobj1.c neededobj2.c neededobj3.c neededobj4.c \
neededobj5.c neededobj6.c \
unload2mod.c unload2dep.c ltglobmod1.c ltglobmod2.c \ unload2mod.c unload2dep.c ltglobmod1.c ltglobmod2.c \
testobj.h vismod.h testobj.h vismod.h
@ -100,7 +101,7 @@ tests = loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
constload1 order $(tests-vis-$(have-protected)) noload filter unload \ constload1 order $(tests-vis-$(have-protected)) noload filter unload \
reldep reldep2 reldep3 next $(tests-nodelete-$(have-z-nodelete)) \ reldep reldep2 reldep3 next $(tests-nodelete-$(have-z-nodelete)) \
$(tests-nodlopen-$(have-z-nodlopen)) neededtest neededtest2 \ $(tests-nodlopen-$(have-z-nodlopen)) neededtest neededtest2 \
neededtest3 unload2 lateglobal neededtest3 neededtest4 unload2 lateglobal
test-srcs = tst-pathopt test-srcs = tst-pathopt
tests-vis-yes = vismain tests-vis-yes = vismain
tests-nodelete-yes = nodelete tests-nodelete-yes = nodelete
@ -113,6 +114,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
$(modules-nodlopen-$(have-z-nodlopen)) filtmod1 filtmod2 \ $(modules-nodlopen-$(have-z-nodlopen)) filtmod1 filtmod2 \
reldepmod1 reldepmod2 reldepmod3 reldepmod4 nextmod1 nextmod2 \ reldepmod1 reldepmod2 reldepmod3 reldepmod4 nextmod1 nextmod2 \
neededobj1 neededobj2 neededobj3 neededobj4 \ neededobj1 neededobj2 neededobj3 neededobj4 \
neededobj5 neededobj6 \
unload2mod unload2dep ltglobmod1 ltglobmod2 pathoptobj unload2mod unload2dep ltglobmod1 ltglobmod2 pathoptobj
modules-vis-yes = vismod1 vismod2 vismod3 modules-vis-yes = vismod1 vismod2 vismod3
modules-nodelete-yes = nodelmod1 nodelmod2 nodelmod3 nodelmod4 modules-nodelete-yes = nodelmod1 nodelmod2 nodelmod3 nodelmod4
@ -263,6 +265,7 @@ $(objpfx)neededobj2.so: $(objpfx)neededobj1.so $(libdl)
$(objpfx)neededobj3.so: $(objpfx)neededobj1.so $(objpfx)neededobj2.so $(libdl) $(objpfx)neededobj3.so: $(objpfx)neededobj1.so $(objpfx)neededobj2.so $(libdl)
$(objpfx)neededobj4.so: $(objpfx)neededobj1.so $(objpfx)neededobj2.so \ $(objpfx)neededobj4.so: $(objpfx)neededobj1.so $(objpfx)neededobj2.so \
$(objpfx)neededobj3.so $(libdl) $(objpfx)neededobj3.so $(libdl)
$(objpfx)neededobj6.so: $(objpfx)neededobj5.so
$(objpfx)unload2mod.so: $(objpfx)unload2dep.so $(objpfx)unload2mod.so: $(objpfx)unload2dep.so
$(objpfx)ltglobmod2.so: $(libdl) $(objpfx)ltglobmod2.so: $(libdl)
@ -287,6 +290,10 @@ $(objpfx)neededtest3: $(libdl)
$(objpfx)neededtest3.out: $(objpfx)neededobj1.so $(objpfx)neededobj2.so \ $(objpfx)neededtest3.out: $(objpfx)neededobj1.so $(objpfx)neededobj2.so \
$(objpfx)neededobj3.so $(objpfx)neededobj4.so $(objpfx)neededobj3.so $(objpfx)neededobj4.so
neededtest4-ENV = LC_ALL=C LANGUAGE=C
$(objpfx)neededtest4: $(libdl) $(objpfx)neededobj1.so
$(objpfx)neededtest4.out: $(objpfx)neededobj5.so $(objpfx)neededobj6.so
$(objpfx)restest1: $(objpfx)testobj1.so $(objpfx)testobj1_1.so $(libdl) $(objpfx)restest1: $(objpfx)testobj1.so $(objpfx)testobj1_1.so $(libdl)
LDFLAGS-restest1 = -rdynamic LDFLAGS-restest1 = -rdynamic

View File

@ -55,7 +55,7 @@ _dl_close (void *_map)
unsigned int *new_opencount; unsigned int *new_opencount;
/* First see whether we can remove the object at all. */ /* First see whether we can remove the object at all. */
if (map->l_flags_1 & DF_1_NODELETE) if ((map->l_flags_1 & DF_1_NODELETE) && map->l_init_called)
/* Nope. Do nothing. */ /* Nope. Do nothing. */
return; return;
@ -101,7 +101,7 @@ _dl_close (void *_map)
} }
--new_opencount[0]; --new_opencount[0];
for (i = 1; list[i] != NULL; ++i) for (i = 1; list[i] != NULL; ++i)
if (! (list[i]->l_flags_1 & DF_1_NODELETE) if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called)
/* Decrement counter. */ /* Decrement counter. */
&& --new_opencount[i] == 0 && --new_opencount[i] == 0
/* Test whether this object was also loaded directly. */ /* Test whether this object was also loaded directly. */
@ -113,7 +113,8 @@ _dl_close (void *_map)
struct link_map **dep_list = list[i]->l_searchlist.r_list; struct link_map **dep_list = list[i]->l_searchlist.r_list;
for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j) for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j)
if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE)) if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE)
|| ! dep_list[j]->l_init_called)
{ {
assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist); assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
--new_opencount[dep_list[j]->l_idx]; --new_opencount[dep_list[j]->l_idx];
@ -127,7 +128,7 @@ _dl_close (void *_map)
struct link_map *imap = list[i]; struct link_map *imap = list[i];
if (new_opencount[i] == 0 && imap->l_type == lt_loaded if (new_opencount[i] == 0 && imap->l_type == lt_loaded
&& (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY]) && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
&& ! (imap->l_flags_1 & DF_1_NODELETE) && (! (imap->l_flags_1 & DF_1_NODELETE) || ! imap->l_init_called)
/* Skip any half-cooked objects that were never initialized. */ /* Skip any half-cooked objects that were never initialized. */
&& imap->l_init_called) && imap->l_init_called)
{ {

View File

@ -141,6 +141,10 @@ _dl_map_object_deps (struct link_map *map,
struct list known[1 + npreloads + 1]; struct list known[1 + npreloads + 1];
struct list *runp, *utail, *dtail; struct list *runp, *utail, *dtail;
unsigned int nlist, nduplist, i; unsigned int nlist, nduplist, i;
/* Object name. */
const char *name;
int errno_saved;
int errno_reason;
auto inline void preload (struct link_map *map); auto inline void preload (struct link_map *map);
@ -192,6 +196,10 @@ _dl_map_object_deps (struct link_map *map,
The whole process is complicated by the fact that we better The whole process is complicated by the fact that we better
should use alloca for the temporary list elements. But using should use alloca for the temporary list elements. But using
alloca means we cannot use recursive function calls. */ alloca means we cannot use recursive function calls. */
errno_saved = errno;
errno_reason = 0;
errno = 0;
name = NULL;
for (runp = known; runp; ) for (runp = known; runp; )
{ {
struct link_map *l = runp->map; struct link_map *l = runp->map;
@ -227,15 +235,24 @@ _dl_map_object_deps (struct link_map *map,
struct link_map *dep; struct link_map *dep;
/* Allocate new entry. */ /* Allocate new entry. */
struct list *newp; struct list *newp;
/* Object name. */ const char *objname;
const char *name; const char *errstring;
/* Recognize DSTs. */ /* Recognize DSTs. */
name = expand_dst (l, strtab + d->d_un.d_val, 0); name = expand_dst (l, strtab + d->d_un.d_val, 0);
/* Store the tag in the argument structure. */
args.name = name;
dep = _dl_map_object (l, name, 0, if (_dl_catch_error (&objname, &errstring, openaux, &args))
l->l_type == lt_executable ? lt_library : {
l->l_type, trace_mode, 0); if (errno)
errno_reason = errno;
else
errno_reason = -1;
goto out;
}
else
dep = args.aux;
/* Add it in any case to the duplicate list. */ /* Add it in any case to the duplicate list. */
newp = alloca (sizeof (struct list)); newp = alloca (sizeof (struct list));
@ -266,18 +283,15 @@ _dl_map_object_deps (struct link_map *map,
const char *objname; const char *objname;
const char *errstring; const char *errstring;
struct list *newp; struct list *newp;
/* Object name. */
const char *name;
/* Recognize DSTs. */ /* Recognize DSTs. */
name = expand_dst (l, strtab + d->d_un.d_val, name = expand_dst (l, strtab + d->d_un.d_val,
d->d_tag == DT_AUXILIARY); d->d_tag == DT_AUXILIARY);
/* Store the tag in the argument structure. */
args.name = name;
if (d->d_tag == DT_AUXILIARY) if (d->d_tag == DT_AUXILIARY)
{ {
/* Store the tag in the argument structure. */
args.name = name;
/* Say that we are about to load an auxiliary library. */ /* Say that we are about to load an auxiliary library. */
if (__builtin_expect (_dl_debug_libs, 0)) if (__builtin_expect (_dl_debug_libs, 0))
_dl_debug_message (1, "load auxiliary object=", _dl_debug_message (1, "load auxiliary object=",
@ -310,10 +324,14 @@ _dl_map_object_deps (struct link_map *map,
"\n", NULL); "\n", NULL);
/* For filter objects the dependency must be available. */ /* For filter objects the dependency must be available. */
args.aux = _dl_map_object (l, name, 0, if (_dl_catch_error (&objname, &errstring, openaux, &args))
(l->l_type == lt_executable {
? lt_library : l->l_type), if (errno)
trace_mode, 0); errno_reason = errno;
else
errno_reason = -1;
goto out;
}
} }
/* The auxiliary object is actually available. /* The auxiliary object is actually available.
@ -460,6 +478,10 @@ _dl_map_object_deps (struct link_map *map,
while (runp != NULL && runp->done); while (runp != NULL && runp->done);
} }
out:
if (errno == 0 && errno_saved != 0)
__set_errno (errno_saved);
if (map->l_initfini != NULL && map->l_type == lt_loaded) if (map->l_initfini != NULL && map->l_type == lt_loaded)
{ {
/* This object was previously loaded as a dependency and we have /* This object was previously loaded as a dependency and we have
@ -558,4 +580,8 @@ _dl_map_object_deps (struct link_map *map,
} }
/* Terminate the list of dependencies. */ /* Terminate the list of dependencies. */
map->l_initfini[nlist] = NULL; map->l_initfini[nlist] = NULL;
if (errno_reason)
_dl_signal_error (errno_reason == -1 ? 0 : errno_reason,
name ?: "", N_("cannot load shared object file"));
} }

View File

@ -396,7 +396,17 @@ _dl_open (const char *file, int mode, const void *caller)
/* Remove the object from memory. It may be in an inconsistent /* Remove the object from memory. It may be in an inconsistent
state if relocation failed, for example. */ state if relocation failed, for example. */
if (args.map) if (args.map)
_dl_close (args.map); {
int i;
/* Increment open counters for all objects which did not get
correctly loaded. */
for (i = 0; i < args.map->l_searchlist.r_nlist; ++i)
if (args.map->l_searchlist.r_list[i]->l_opencount == 0)
args.map->l_searchlist.r_list[i]->l_opencount = 1;
_dl_close (args.map);
}
/* Make a local copy of the error string so that we can release the /* Make a local copy of the error string so that we can release the
memory allocated for it. */ memory allocated for it. */

5
elf/neededobj5.c Normal file
View File

@ -0,0 +1,5 @@
extern void a1_function (void);
void a1_function (void)
{
}

7
elf/neededobj6.c Normal file
View File

@ -0,0 +1,7 @@
extern void a1_function (void);
extern void a2_function (void);
void a2_function (void)
{
a1_function ();
}

156
elf/neededtest4.c Normal file
View File

@ -0,0 +1,156 @@
#include <dlfcn.h>
#include <libintl.h>
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int
check_loaded_objects (const char **loaded)
{
struct link_map *lm;
int n;
int *found = NULL;
int errors = 0;
for (n = 0; loaded[n]; n++)
/* NOTHING */;
if (n)
{
found = (int *) alloca (sizeof (int) * n);
memset (found, 0, sizeof (int) * n);
}
printf(" Name\n");
printf(" --------------------------------------------------------\n");
for (lm = _r_debug.r_map; lm; lm = lm->l_next)
{
if (lm->l_name && lm->l_name[0])
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_opencount);
if (lm->l_type == lt_loaded && lm->l_name)
{
int match = 0;
for (n = 0; loaded[n] != NULL; n++)
{
if (strcmp (basename (loaded[n]), basename (lm->l_name)) == 0)
{
found[n] = 1;
match = 1;
break;
}
}
if (match == 0)
{
++errors;
printf ("ERRORS: %s is not unloaded\n", lm->l_name);
}
}
}
for (n = 0; loaded[n] != NULL; n++)
{
if (found[n] == 0)
{
++errors;
printf ("ERRORS: %s is not loaded\n", loaded[n]);
}
}
return errors;
}
extern void c_function (void);
extern char *dirname (__const char *__filename);
int
main (int argc, char **argv)
{
void *obj;
const char *loaded[] = { NULL, NULL, NULL};
int errors = 0;
void (*f) (void);
const char *dir = dirname (argv [0]);
char *oldfilename;
char *newfilename;
c_function ();
printf ("\nThis is what is in memory now:\n");
errors += check_loaded_objects (loaded);
printf( "Loading shared object neededobj6.so\n");
obj = dlopen( "neededobj6.so", RTLD_LAZY);
if (obj == NULL)
{
printf ("%s\n", dlerror ());
exit (1);
}
f = dlsym (obj, "a2_function");
if (f == NULL)
{
printf ("%s\n", dlerror ());
exit (1);
}
f ();
loaded[0] = "neededobj5.so";
loaded[1] = "neededobj6.so";
errors += check_loaded_objects (loaded);
printf ("Closing neededobj6.so\n");
dlclose (obj);
loaded[0] = NULL;
errors += check_loaded_objects (loaded);
printf ("Rename neededobj5.so\n");
oldfilename = alloca (strlen (dir) + 1 + sizeof ("neededobj5.so"));
strcpy (oldfilename, dir);
strcat (oldfilename, "/");
strcat (oldfilename, "neededobj5.so");
newfilename = alloca (strlen (oldfilename) + sizeof (".renamed"));
strcpy (newfilename, oldfilename);
strcat (newfilename, ".renamed");
if (rename (oldfilename, newfilename))
{
perror ("rename");
exit (1);
}
printf( "Loading shared object neededobj6.so\n");
obj = dlopen( "neededobj6.so", RTLD_LAZY);
if (obj == NULL)
printf ("%s\n", dlerror ());
else
{
printf ("neededobj6.so should fail to load\n");
exit (1);
}
printf( "Loading shared object neededobj1.so\n");
obj = dlopen( "neededobj1.so", RTLD_LAZY);
if (obj == NULL)
{
printf ("%s\n", dlerror ());
exit (1);
}
errors += check_loaded_objects (loaded);
f = dlsym (obj, "c_function");
if (f == NULL)
{
printf ("%s\n", dlerror ());
exit (1);
}
f ();
printf ("Restore neededobj5.so\n");
if (rename (newfilename, oldfilename))
{
perror ("rename");
exit (1);
}
if (errors != 0)
printf ("%d errors found\n", errors);
return errors;
}