From b2a30ee8d209154efc367db11b4167a5d6db605f Mon Sep 17 00:00:00 2001
From: Dmitriy Ivanov <dimitry@google.com>
Date: Thu, 4 Sep 2014 18:23:00 -0700
Subject: [PATCH] Fix order of soinfo links (repairs libcxx tests).

Change-Id: Iee9de09657351cd6a7512784ca797e4b84cdd98b
---
 linker/linker.cpp                             |  4 +--
 tests/Android.mk                              |  1 +
 tests/dlfcn_test.cpp                          | 28 +++++++++++++++++++
 tests/libs/Android.mk                         | 23 +++++++++++++++
 ...pen_testlib_relo_check_dt_needed_order.cpp | 21 ++++++++++++++
 ...n_testlib_relo_check_dt_needed_order_1.cpp | 19 +++++++++++++
 ...n_testlib_relo_check_dt_needed_order_2.cpp | 19 +++++++++++++
 7 files changed, 113 insertions(+), 2 deletions(-)
 create mode 100644 tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp
 create mode 100644 tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp
 create mode 100644 tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp

diff --git a/linker/linker.cpp b/linker/linker.cpp
index 610489ea5..ac470a54b 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1778,8 +1778,8 @@ void soinfo::CallDestructors() {
 
 void soinfo::add_child(soinfo* child) {
   if (has_min_version(0)) {
-    this->children.push_front(child);
-    child->parents.push_front(this);
+    child->parents.push_back(this);
+    this->children.push_back(child);
   }
 }
 
diff --git a/tests/Android.mk b/tests/Android.mk
index cb588d78e..49efdad9a 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -264,6 +264,7 @@ bionic-unit-tests_ldflags := \
     -Wl,-u,DlSymTestFunction \
 
 bionic-unit-tests_c_includes := \
+    bionic/libc \
     $(call include-path-for, libpagemap) \
 
 bionic-unit-tests_shared_libraries_target := \
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index ccfd74319..3568f8fc1 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -22,6 +22,8 @@
 #include <stdio.h>
 #include <stdint.h>
 
+#include "private/ScopeGuard.h"
+
 #include <string>
 
 #define ASSERT_SUBSTR(needle, haystack) \
@@ -130,6 +132,32 @@ TEST(dlfcn, ifunc_ctor_call) {
 }
 #endif
 
+TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
+  // This is the structure of the test library and
+  // its dt_needed libraries
+  // libtest_relo_check_dt_needed_order.so
+  // |
+  // +-> libtest_relo_check_dt_needed_order_1.so
+  // |
+  // +-> libtest_relo_check_dt_needed_order_2.so
+  //
+  // The root library references relo_test_get_answer_lib - which is defined
+  // in both dt_needed libraries, the correct relocation should
+  // use the function defined in libtest_relo_check_dt_needed_order_1.so
+  void* handle = nullptr;
+  auto guard = create_scope_guard([&]() {
+    dlclose(handle);
+  });
+
+  handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  typedef int (*fn_t) (void);
+  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+  ASSERT_EQ(1, fn());
+}
+
 TEST(dlfcn, dlopen_check_order) {
   // Here is how the test library and its dt_needed
   // libraries are arranged
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index 2ceb15b9e..be6565bab 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -256,6 +256,29 @@ build_type := target
 build_target := SHARED_LIBRARY
 include $(TEST_PATH)/Android.build.mk
 
+# -----------------------------------------------------------------------------
+# libtest_relo_check_dt_needed_order.so
+# |
+# +-> libtest_relo_check_dt_needed_order_1.so
+# |
+# +-> libtest_relo_check_dt_needed_order_2.so
+# -----------------------------------------------------------------------------
+libtest_relo_check_dt_needed_order_shared_libraries := \
+    libtest_relo_check_dt_needed_order_1 libtest_relo_check_dt_needed_order_2
+
+libtest_relo_check_dt_needed_order_src_files := dlopen_testlib_relo_check_dt_needed_order.cpp
+libtest_relo_check_dt_needed_order_1_src_files := dlopen_testlib_relo_check_dt_needed_order_1.cpp
+libtest_relo_check_dt_needed_order_2_src_files := dlopen_testlib_relo_check_dt_needed_order_2.cpp
+build_type := target
+build_target := SHARED_LIBRARY
+
+module := libtest_relo_check_dt_needed_order
+include $(TEST_PATH)/Android.build.mk
+module := libtest_relo_check_dt_needed_order_1
+include $(TEST_PATH)/Android.build.mk
+module := libtest_relo_check_dt_needed_order_2
+include $(TEST_PATH)/Android.build.mk
+
 # -----------------------------------------------------------------------------
 # Library with dependency used by dlfcn tests
 # -----------------------------------------------------------------------------
diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp
new file mode 100644
index 000000000..d8fb543ad
--- /dev/null
+++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C" int relo_test_get_answer_lib();
+
+extern "C" int relo_test_get_answer() {
+  return relo_test_get_answer_lib();
+}
diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp
new file mode 100644
index 000000000..4c877d0a1
--- /dev/null
+++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C" int relo_test_get_answer_lib() {
+  return 1;
+}
diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp
new file mode 100644
index 000000000..10288a086
--- /dev/null
+++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C" int relo_test_get_answer_lib() {
+  return 2;
+}