From: Zhiting Zhu <zhiti...@cs.utexas.edu>
Committer: Waldemar Kozaczuk <jwkozac...@gmail.com>
Branch: master

Add dlsym tests

This patch includes a module called dl_tests which clones the bionic
and compile the needed library files.

Signed-off-by: Zhiting Zhu <zhiti...@cs.utexas.edu>
Message-Id: <20200110071641.110196-1-zhiti...@cs.utexas.edu>

---
diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -46,4 +46,6 @@ modules/httpserver-jvm-plugin/obj/
 modules/libtools/*.so
 modules/libtools/*.o
 modules/libyaml/usr.manifest
+modules/dl_tests/bionic/
+modules/dl_tests/usr.manifest
 .idea
diff --git a/modules/dl_tests/Makefile b/modules/dl_tests/Makefile
--- a/modules/dl_tests/Makefile
+++ b/modules/dl_tests/Makefile
@@ -0,0 +1,118 @@
+module: usr.manifest build_all
+
+src := $(OSV_BASE)
+out := $(OSV_BUILD_PATH)
+arch := $(ARCH)
+fs_type := $(fs_type)
+bionic_test_libs := $(src)/modules/dl_tests/bionic/tests/libs
+
+quiet = $(if $V, $1, @echo " $2"; $1)
+very-quiet = $(if $V, $1, @$1)
+makedir = $(call very-quiet, mkdir -p $(dir $@))
+
+autodepend = -MD -MT $@ -MP
+
+INCLUDES = -I$(src)/arch/$(ARCH) -I$(src) -I$(src)/include \
+       -I$(src)/arch/common -isystem $(src)/include/glibc-compat \
+ $(shell $(CXX) -E -xc++ - -v </dev/null 2>&1 | awk '/^End/ {exit} /^ .*c\+\+/ {print "-isystem" $$0}') \
+       -isystem $(src)/include/api -isystem $(src)/include/api/$(ARCH) \
+       -isystem $(out)/gen/include
+
+COMMON = $(autodepend) $(INCLUDES) -g -O2 -fPIC -DBOOST_TEST_DYN_LINK \
+       -U _FORTIFY_SOURCE -D_KERNEL -D__OSV__ -DCONF_debug_memory=0 \
+       -Wall -Wno-pointer-arith -Wformat=0 -Wno-format-security
+
+LIBS =
+
+CXXFLAGS = -std=gnu++11 $(COMMON)
+CFLAGS = -std=gnu99 $(COMMON)
+
+tests := libtest_simple.so libtest_empty.so libtest_dlsym_from_this_grandchild.so \ + libtest_dlsym_from_this_child.so libtest_dlsym_from_this.so libdlext_test.so \
+       libtest_with_dependency.so libtest_check_rtld_next_from_library.so
+
+.PHONY: get_file
+get_file:
+       if cd $(src)/modules/dl_tests/bionic; then \
+               git pull; \
+       else \
+ git clone --depth=1 https://android.googlesource.com/platform/bionic $(src)/modules/dl_tests/bionic; \
+       fi
+
+all_tests := $(tests:%=dl_tests/%)
+
+build_all:
+       $(MAKE) get_file
+       $(MAKE) $(all_tests:%=$(out)/%)
+.PHONY: build_all
+
+$(out)/dl_tests/libtest_simple.so: $(bionic_test_libs)/dlopen_testlib_simple.cpp
+       $(makedir)
+ $(call quiet, cd $(out); $(CXX) $(CXXFLAGS) -D__SHARED_OBJECT__=1 -shared -o $@ $<, CXX dl_tests/libtest_simple.so)
+
+$(out)/dl_tests/libtest_empty.so: $(bionic_test_libs)/empty.cpp
+       $(makedir)
+ $(call quiet, cd $(out); $(CXX) $(CXXFLAGS) -D__SHARED_OBJECT__=1 -shared -o $@ $<, CXX dl_tests/libtest_empty.so)
+
+$(out)/dl_tests/libtest_check_rtld_next_from_library.so: $(bionic_test_libs)/check_rtld_next_from_library.cpp
+       $(makedir)
+ $(call quiet, cd $(out); $(CXX) $(CXXFLAGS) -D__SHARED_OBJECT__=1 -shared -o $@ $<, CXX dl_tests/libtest_check_rtld_next_from_library.so)
+
+$(out)/dl_tests/libtest_dlsym_from_this_grandchild.so: $(bionic_test_libs)/dlsym_from_this_symbol2.cpp
+       $(makedir)
+ $(call quiet, cd $(out); $(CXX) $(CXXFLAGS) -D__SHARED_OBJECT__=1 -shared -o $@ $<, CXX dl_tests/libtest_dlsym_from_this_grandchild.so)
+
+$(out)/dl_tests/libtest_dlsym_from_this_child.so: COMMON += -Wl,--no-as-needed -ltest_dlsym_from_this_grandchild -L=$(out)/dl_tests -L=/usr/lib -Wl,-rpath . -Wl,-rpath / -Wl,-rpath /usr/lib
+$(out)/dl_tests/libtest_dlsym_from_this_child.so: \
+               $(bionic_test_libs)/dlsym_from_this_functions.cpp
+       $(MAKE) $(out)/dl_tests/libtest_dlsym_from_this_grandchild.so
+       $(makedir)
+ $(call quiet, cd $(out); $(CXX) $(CXXFLAGS) -D__SHARED_OBJECT__=1 -shared -o $@ $<, CXX dl_tests/libtest_dlsym_from_this_child.so)
+
+$(out)/dl_tests/libtest_dlsym_from_this.so: COMMON += -Wl,--no-as-needed -ltest_dlsym_from_this_child -L=$(out)/dl_tests -L=/usr/lib -Wl,-rpath . -Wl,-rpath / -Wl,-rpath /usr/lib
+$(out)/dl_tests/libtest_dlsym_from_this.so: \
+               $(bionic_test_libs)/dlsym_from_this_symbol.cpp
+       $(MAKE) $(out)/dl_tests/libtest_dlsym_from_this_child.so
+       $(makedir)
+ $(call quiet, cd $(out); $(CXX) $(CXXFLAGS) -D__SHARED_OBJECT__=1 -shared -o $@ $<, CXX dl_tests/libtest_dlsym_from_this.so)
+
+$(out)/dl_tests/libdlext_test.so: COMMON += -Wl,-z,relro -Wl,--no-as-needed -ltest_simple -L=$(out)/dl_tests -L=/usr/lib -Wl,-rpath . -Wl,-rpath / -Wl,-rpath /usr/lib
+$(out)/dl_tests/libdlext_test.so: \
+               $(bionic_test_libs)/dlext_test_library.cpp
+       $(MAKE) $(out)/dl_tests/libtest_simple.so
+       $(makedir)
+ $(call quiet, cd $(out); $(CXX) $(CXXFLAGS) -D__SHARED_OBJECT__=1 -shared -o $@ $<, CXX dl_tests/libdlext_test.so)
+
+$(out)/dl_tests/libtest_with_dependency.so: COMMON += -Wl,--no-as-needed -ldlext_test -L=$(out)/dl_tests -L=/usr/lib -Wl,-rpath . -Wl,-rpath / -Wl,-rpath /usr/lib
+$(out)/dl_tests/libtest_with_dependency.so: \
+               $(bionic_test_libs)/dlopen_testlib_simple.cpp
+       $(MAKE) $(out)/dl_tests/libdlext_test.so
+       $(makedir)
+ $(call quiet, cd $(out); $(CXX) $(CXXFLAGS) -D__SHARED_OBJECT__=1 -shared -o $@ $<, CXX dl_tests/libtest_with_dependency.so)
+
+usr.manifest: build_all FORCE
+       @echo "/usr/lib/libtest_simple.so: ./dl_tests/libtest_simple.so" > $@
+       @echo "/usr/lib/libtest_empty.so: ./dl_tests/libtest_empty.so" >> $@
+ @echo "/usr/lib/libtest_dlsym_from_this_grandchild.so: ./dl_tests/libtest_dlsym_from_this_grandchild.so"
$@
+ @echo "/usr/lib/libtest_dlsym_from_this_child.so: ./dl_tests/libtest_dlsym_from_this_child.so"
$@
+ @echo "/usr/lib/libtest_dlsym_from_this.so: ./dl_tests/libtest_dlsym_from_this.so"
$@
+       @echo "/usr/lib/libdlext_test.so: ./dl_tests/libdlext_test.so" >> $@
+ @echo "/usr/lib/libtest_with_dependency.so: ./dl_tests/libtest_with_dependency.so"
$@
+ @echo "/usr/lib/libtest_check_rtld_next_from_library.so: ./dl_tests/libtest_check_rtld_next_from_library.so"
$@
+       @echo "/tests/libtest_simple.so: ./dl_tests/libtest_simple.so" >> $@
+       @echo "/tests/libtest_empty.so: ./dl_tests/libtest_empty.so" >> $@
+ @echo "/tests/libtest_dlsym_from_this_grandchild.so: ./dl_tests/libtest_dlsym_from_this_grandchild.so"
$@
+ @echo "/tests/libtest_dlsym_from_this_child.so: ./dl_tests/libtest_dlsym_from_this_child.so"
$@
+ @echo "/tests/libtest_dlsym_from_this.so: ./dl_tests/libtest_dlsym_from_this.so"
$@
+       @echo "/tests/libdlext_test.so: ./dl_tests/libdlext_test.so" >> $@
+ @echo "/tests/libtest_with_dependency.so: ./dl_tests/libtest_with_dependency.so"
$@
+ @echo "/tests/libtest_check_rtld_next_from_library.so: ./dl_tests/libtest_check_rtld_next_from_library.so"
$@
+.PHONY: FORCE
+FORCE:
+
+clean:
+       -rm -f usr.manifest
+
+ifneq ($(MAKECMDGOALS),clean)
+include $(shell test -d $(out)/dl_tests && find $(out)/dl_tests -name '*.d')
+endif
diff --git a/modules/tests/Makefile b/modules/tests/Makefile
--- a/modules/tests/Makefile
+++ b/modules/tests/Makefile
@@ -147,6 +147,8 @@ $(out)/tests/tst-mmap.so: COMMON += -fuse-ld=bfd
 $(out)/tests/tst-elf-permissions.so: COMMON += -fuse-ld=bfd
 $(out)/tests/tst-tls.so: COMMON += -fuse-ld=bfd

+$(out)/tests/tst-dlfcn.so: COMMON += -rdynamic -ldl
+
 $(out)/tests/tst-tls.so: \
                $(src)/tests/tst-tls.cc \
                $(out)/tests/libtls.so
diff --git a/modules/tests/module.py b/modules/tests/module.py
--- a/modules/tests/module.py
+++ b/modules/tests/module.py
@@ -1,3 +1,4 @@
 from osv.modules import api

 api.require('java-tests')
+api.require('dl_tests')
diff --git a/tests/tst-dlfcn.cc b/tests/tst-dlfcn.cc
--- a/tests/tst-dlfcn.cc
+++ b/tests/tst-dlfcn.cc
@@ -10,6 +10,16 @@
 #include <dlfcn.h>

 #include <boost/test/unit_test.hpp>
+namespace utf = boost::unit_test;
+
+const bool rtld_next = false;
+const bool deep_lookup = false;
+
+static bool called = false;
+extern "C" void DlSymTestFunction()
+{
+    called = true;
+}

 BOOST_AUTO_TEST_CASE(test_dlopen_with_null_as_filename)
 {
@@ -53,3 +63,238 @@ BOOST_AUTO_TEST_CASE(test_dladdr)
     BOOST_CHECK_EQUAL("vfprintf", info.dli_sname);
     BOOST_CHECK_EQUAL(vfprintf, info.dli_saddr);
 }
+
+BOOST_AUTO_TEST_CASE(test_dlsym_in_executable)
+{
+    dlerror();
+    void* self = dlopen(NULL, RTLD_NOW);
+    BOOST_REQUIRE_NE(self, nullptr);
+    BOOST_REQUIRE_EQUAL(dlerror(), nullptr);
+
+    void* sym = dlsym(self, "DlSymTestFunction");
+    BOOST_REQUIRE_NE(sym, nullptr);
+
+    void (*function)() = reinterpret_cast<void(*)()>(sym);
+
+    called = false;
+    function();
+    BOOST_REQUIRE_EQUAL(called, true);
+    BOOST_CHECK_EQUAL(0, dlclose(self));
+}
+
+BOOST_AUTO_TEST_CASE(test_dlsym_from_sofile,
+        *utf::enable_if<rtld_next>())
+{
+    dlerror();
+ void* handle = dlopen("/tests/libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL);
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE_NE(handle, nullptr);
+
+ // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
+    void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
+    (void)symbol;
+ // TODO: dlopen ignores all the flags; the current implementation assumes the flag to be RTLD_GLOBAL but the default should be RTLD_LOCAL
+    //       Should reenable the test after flags are implemented
+    // BOOST_REQUIRE_EQUAL(symbol, nullptr);
+    // auto err_msg = std::string(dlerror());
+    // BOOST_TEST_CONTEXT(err_msg)
+ // BOOST_REQUIRE_NE(err_msg.find("dlsym: symbol test_dlsym_symbol not found"),
+    //     std::string::npos);
+ // BOOST_REQUIRE_NE(err_msg.find("undefined symbol: test_dlsym_symbol"),
+    //         std::string::npos);
+
+    typedef int* (*fn_t)();
+    fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE_NE(lookup_dlsym_symbol_using_RTLD_DEFAULT, nullptr);
+
+    int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE_NE(ptr, nullptr);
+    BOOST_REQUIRE_EQUAL(42, *ptr);
+
+    fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr);
+
+    ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(ptr != nullptr);
+    BOOST_REQUIRE_EQUAL(44, *ptr);
+
+    fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr);
+
+    ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(ptr != nullptr);
+    BOOST_REQUIRE_EQUAL(43, *ptr);
+
+    dlclose(handle);
+}
+
+BOOST_AUTO_TEST_CASE(test_dlsym_from_sofile_with_preload,
+        *utf::enable_if<deep_lookup>())
+{
+ void* preload = dlopen("/tests/libtest_dlsym_from_this_grandchild.so", RTLD_NOW | RTLD_LOCAL);
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(preload != nullptr);
+
+ void* handle = dlopen("/tests/libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL);
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(handle != nullptr);
+
+ // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
+    void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
+    (void)symbol;
+ // TODO: dlopen ignores all the flags; the current implementation assumes the flag to be RTLD_GLOBAL but the default should be RTLD_LOCAL
+    //       Should reenable the test after flags are implemented
+    // BOOST_REQUIRE_EQUAL(symbol, nullptr);
+    // auto err_msg = std::string(dlerror());
+    // BOOST_TEST_CONTEXT(err_msg)
+ // BOOST_REQUIRE_NE(err_msg.find("dlsym: symbol test_dlsym_symbol not found"),
+    //      std::string::npos);
+ // BOOST_REQUIRE_NE(err_msg.find("undefined symbol: test_dlsym_symbol"),
+    //         std::string::npos);
+
+    typedef int* (*fn_t)();
+    fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr);
+
+    int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(ptr != nullptr);
+    BOOST_REQUIRE_EQUAL(42, *ptr);
+
+    fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr);
+
+    ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE_NE(ptr, nullptr);
+    BOOST_REQUIRE_EQUAL(44, *ptr);
+
+    fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr);
+
+    ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(ptr != nullptr);
+    BOOST_REQUIRE_EQUAL(43, *ptr);
+
+    dlclose(handle);
+    dlclose(preload);
+}
+
+BOOST_AUTO_TEST_CASE(dlsym_handle_global_sym)
+{
+    // check that we do not look into global group
+    // when looking up symbol by handle
+    void* handle = dlopen("/tests/libtest_empty.so", RTLD_NOW);
+    dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL);
+    void* sym = dlsym(handle, "getRandomNumber");
+    BOOST_REQUIRE(sym == nullptr);
+    auto err_msg = std::string(dlerror());
+    BOOST_TEST_CONTEXT(err_msg)
+ BOOST_REQUIRE_NE(err_msg.find("dlsym: symbol getRandomNumber not found"),
+            std::string::npos);
+    // BOOST_REQUIRE_NE(err_msg.find("undefined symbol: getRandomNumber"),
+    //         std::string::npos);
+
+    sym = dlsym(handle, "DlSymTestFunction");
+    BOOST_REQUIRE(sym == nullptr);
+    err_msg = std::string(dlerror());
+    BOOST_TEST_CONTEXT(err_msg)
+ BOOST_REQUIRE_NE(err_msg.find("dlsym: symbol DlSymTestFunction not found"),
+            std::string::npos);
+ // BOOST_REQUIRE_NE(err_msg.find("undefined symbol: DlSymTestFunction"),
+    //         std::string::npos);
+    dlclose(handle);
+}
+
+BOOST_AUTO_TEST_CASE(dlsym_handle_empty_symbol)
+{
+    // check that dlsym of an empty symbol fails (see http://b/33530622)
+    void* handle = dlopen("/tests/libtest_dlsym_from_this.so", RTLD_NOW);
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(handle != nullptr);
+    void* sym = dlsym(handle, "");
+    BOOST_REQUIRE(sym == nullptr);
+    auto err_msg = std::string(dlerror());
+    BOOST_TEST_CONTEXT(err_msg)
+    BOOST_REQUIRE_NE(err_msg.find("dlsym: symbol  not found"),
+            std::string::npos);
+    // BOOST_REQUIRE_NE(err_msg.find("undefined symbol: "),
+    //         std::string::npos);
+    dlclose(handle);
+}
+
+BOOST_AUTO_TEST_CASE(dlsym_with_dependencies,
+        *utf::enable_if<deep_lookup>())
+{
+    void* handle = dlopen("/tests/libtest_with_dependency.so", RTLD_NOW);
+    BOOST_REQUIRE(handle != nullptr);
+    dlerror();
+    // This symbol is in DT_NEEDED library.
+    void* sym = dlsym(handle, "getRandomNumber");
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE_NE(sym, nullptr);
+    int (*fn)(void);
+    fn = reinterpret_cast<int (*)(void)>(sym);
+    BOOST_CHECK_EQUAL(4, fn());
+    dlclose(handle);
+}
+
+BOOST_AUTO_TEST_CASE(rtld_default_unknown_symbol)
+{
+    void* addr = dlsym(RTLD_DEFAULT, "UNKNOWN");
+    BOOST_REQUIRE_EQUAL(addr, nullptr);
+}
+
+BOOST_AUTO_TEST_CASE(rtld_default_fclose)
+{
+    void* addr = dlsym(RTLD_DEFAULT, "fclose");
+    BOOST_REQUIRE_NE(addr, nullptr);
+}
+
+BOOST_AUTO_TEST_CASE(rtld_next_unknown_symbol,
+        *utf::enable_if<rtld_next>())
+{
+    void* addr = dlsym(RTLD_NEXT, "UNKNOWN");
+    BOOST_REQUIRE_EQUAL(addr, nullptr);
+}
+
+BOOST_AUTO_TEST_CASE(rtld_next_fclose,
+        *utf::enable_if<rtld_next>())
+{
+    void* addr = dlsym(RTLD_NEXT, "fclose");
+    BOOST_REQUIRE_NE(addr, nullptr);
+}
+
+BOOST_AUTO_TEST_CASE(rtld_next_from_lib, *utf::enable_if<rtld_next>())
+{
+ void* library_with_fclose = dlopen("/tests/libtest_check_rtld_next_from_library.so", RTLD_NOW | RTLD_GLOBAL);
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(library_with_fclose != nullptr);
+    void* expected_addr = dlsym(RTLD_DEFAULT, "fclose");
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(expected_addr != nullptr);
+    typedef void* (*get_libc_fclose_ptr_fn_t)();
+    get_libc_fclose_ptr_fn_t get_libc_fclose_ptr =
+ reinterpret_cast<get_libc_fclose_ptr_fn_t>(dlsym(library_with_fclose, "get_libc_fclose_ptr"));
+    BOOST_TEST_CONTEXT(dlerror())
+    BOOST_REQUIRE(get_libc_fclose_ptr != nullptr);
+    BOOST_REQUIRE_EQUAL(expected_addr, get_libc_fclose_ptr());
+
+    dlclose(library_with_fclose);
+}

--
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/000000000000b41f63059be09e0a%40google.com.

Reply via email to