Browse Source

tests:libdl: add a new test for symbol scope issue in dlclose

Test case to trigger an issue raised by the new symbol scope design,
that was erroneously removing local symbol scope from the global one
too early while dl-closing a shared library.
Based on original test-case by Khem Raj

Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono@st.com>
Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
Reported-by: Khem Raj <raj.khem@gmail.com>
Filippo ARCIDIACONO 13 years ago
parent
commit
ac33828db1
5 changed files with 95 additions and 1 deletions
  1. 22 1
      test/dlopen/Makefile.in
  2. 7 0
      test/dlopen/libA.c
  3. 7 0
      test/dlopen/libB.c
  4. 30 0
      test/dlopen/libC.c
  5. 29 0
      test/dlopen/testscope.c

+ 22 - 1
test/dlopen/Makefile.in

@@ -4,7 +4,8 @@
 # rules need a little love to work with glibc ...
 export UCLIBC_ONLY := 1
 
-TESTS := dltest dltest2 dlstatic test1 test2 test3 dlundef dlafk dladdr
+TESTS := dltest dltest2 dlstatic test1 test2 test3 dlundef dlafk dladdr \
+	testscope
 
 CFLAGS_dltest    := -DLIBNAME="\"./libtest.so\""
 CFLAGS_dltest2   := -DLIBNAME="\"./libtest3.so\""
@@ -18,22 +19,42 @@ LDFLAGS_test1    := -ldl
 LDFLAGS_test2    := -ldl
 LDFLAGS_test3    := -ldl ./libtest1.so ./libtest2.so -Wl,-rpath,.
 LDFLAGS_dladdr   := -ldl
+LDFLAGS_testscope:= -ldl
 
 DEBUG_LIBS := X
 WRAPPER := env $(DEBUG_LIBS)=all LD_LIBRARY_PATH="$$PWD:.:$(LD_LIBRARY_PATH)"
 
+# Build libC.so without -mprefergot compilation flag to force a
+# R_SH_JMP_SLOT relocation instead of R_SH_GLOB_DAT for _libC_fini. This is
+# needed to resolve the _libC_fini symbol when used (by libC.so destructor),
+# whereas with GLOB_DAT relocation the resolution happens in the GOT entry
+# when the libC is loaded, for the same reason remove also the "-z now"
+# linker flag.
+# These are needed to spot the issue test case want raise.
+
+ifeq ($(TARGET_ARCH),sh)
+CFLAGS-OMIT-libC.c = -mprefergot
+endif
+LDFLAGS-OMIT-libC.c = -Wl,-z,now
+
 dltest: libtest.so
 dltest2: libtest3.so
 dlstatic: libstatic.so
 dlundef: libundef.so
 dlafk: libafk.so
+testscope:libA.so
 libafk.so: libafk-temp.so
 LDFLAGS_libafk.so := ./libafk-temp.so -Wl,-rpath,.
 test1: libtest1.so
 test2: libtest1.so libtest2.so
 test3: libtest1.so libtest2.so
 libtest1.so: libtest2.so
+libB.so: libC.so
+libA.so: libB.so
 LDFLAGS_libtest.so := -lpthread
 LDFLAGS_libtest1.so := ./libtest2.so -Wl,-rpath,.
 LDFLAGS_libtest2.so := -Wl,-rpath,.
 LDFLAGS_libtest3.so := -lpthread -Wl,-rpath,.
+LDFLAGS_libC.so := -ldl
+LDFLAGS_libB.so := ./libC.so -Wl,-rpath,.
+LDFLAGS_libA.so := ./libB.so -Wl,-rpath,.

+ 7 - 0
test/dlopen/libA.c

@@ -0,0 +1,7 @@
+extern void libB_func(void);
+
+void libA_func(void);
+void libA_func(void)
+{
+	libB_func();
+}

+ 7 - 0
test/dlopen/libB.c

@@ -0,0 +1,7 @@
+extern void libC_func(void);
+
+void libB_func(void);
+void libB_func(void)
+{
+	libC_func();
+}

+ 30 - 0
test/dlopen/libC.c

@@ -0,0 +1,30 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define LIBNAME "libB.so"
+void _libC_fini(void);
+void _libC_fini(void)
+{
+	printf("libC_fini():finish - atexit()\n");
+}
+
+void libC_fini(void);
+void libC_fini(void)
+{
+	_libC_fini();
+}
+
+void libC_func(void);
+void libC_func(void)
+{
+	void *libB;
+
+	libB = dlopen(LIBNAME, RTLD_LAZY);
+	if (!libB) {
+		fprintf(stderr, "Could not open ./%s: %s\n", LIBNAME, dlerror());
+		exit(1);
+	}
+
+	atexit(libC_fini);
+}

+ 29 - 0
test/dlopen/testscope.c

@@ -0,0 +1,29 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define LIBNAME "libA.so"
+int main(int argc, char **argv)
+{
+	void *libA;
+	void (*libAfn)(void);
+	char *error;
+
+	libA = dlopen(LIBNAME, RTLD_LAZY);
+	if (!libA) {
+		fprintf(stderr, "Could not open ./%s: %s\n", LIBNAME, dlerror());
+		exit(1);
+	}
+
+	libAfn = dlsym(libA, "libA_func");
+	if ((error = dlerror()) != NULL)  {
+		fprintf(stderr, "Could not locate symbol 'libA_func': %s\n", error);
+		exit(1);
+	}
+
+	libAfn();
+
+	dlclose(libA);
+
+	return EXIT_SUCCESS;
+}