diff options
author | Dimitry Ivanov <dimitry@google.com> | 2017-02-09 13:31:57 -0800 |
---|---|---|
committer | Dimitry Ivanov <dimitry@google.com> | 2017-02-09 14:07:05 -0800 |
commit | ea8f396c59f824993044d9474c2dc04423003c59 (patch) | |
tree | eb39d5e37d3a442b7c2d4f4c3705922b380cd47e | |
parent | 2bfb8c9180603bac97dca2d8e359f71bb11f7126 (diff) | |
download | android_bionic-ea8f396c59f824993044d9474c2dc04423003c59.tar.gz android_bionic-ea8f396c59f824993044d9474c2dc04423003c59.tar.bz2 android_bionic-ea8f396c59f824993044d9474c2dc04423003c59.zip |
Add test checking init/fini call order
This test is checking that loader complies with the order described in
http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#init_fini
Bug: http://b/35201832
Test: bionic-unit-tests --gtest_filter=dl*:Dl*
Test: bionic-unit-tests-glibc --gtest_filter=dl*
Change-Id: I4cdf878c043112442c191e82aa9f5d5077e4d8c4
-rw-r--r-- | tests/dlfcn_test.cpp | 22 | ||||
-rw-r--r-- | tests/libs/Android.bp | 23 | ||||
-rw-r--r-- | tests/libs/dlopen_check_init_fini_child.cpp | 28 | ||||
-rw-r--r-- | tests/libs/dlopen_check_init_fini_grand_child.cpp | 28 | ||||
-rw-r--r-- | tests/libs/dlopen_check_init_fini_root.cpp | 46 |
5 files changed, 147 insertions, 0 deletions
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index a56e3a764..3e9e85ed9 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -1136,6 +1136,28 @@ TEST(dlfcn, dlopen_dlopen_from_ctor) { #endif } +static std::string g_fini_call_order_str; + +static void register_fini_call(const char* s) { + g_fini_call_order_str += s; +} + +TEST(dlfcn, init_fini_call_order) { + void* handle = dlopen("libtest_init_fini_order_root.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr) << dlerror(); + typedef int (*get_init_order_number_t)(); + get_init_order_number_t get_init_order_number = + reinterpret_cast<get_init_order_number_t>(dlsym(handle, "get_init_order_number")); + ASSERT_EQ(321, get_init_order_number()); + + typedef void (*set_fini_callback_t)(void (*f)(const char*)); + set_fini_callback_t set_fini_callback = + reinterpret_cast<set_fini_callback_t>(dlsym(handle, "set_fini_callback")); + set_fini_callback(register_fini_call); + dlclose(handle); + ASSERT_EQ("(root)(child)(grandchild)", g_fini_call_order_str); +} + TEST(dlfcn, symbol_versioning_use_v1) { void* handle = dlopen("libtest_versioned_uselibv1.so", RTLD_NOW); ASSERT_TRUE(handle != nullptr) << dlerror(); diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp index 78027275f..31a09161f 100644 --- a/tests/libs/Android.bp +++ b/tests/libs/Android.bp @@ -448,6 +448,29 @@ cc_test_library { } // ----------------------------------------------------------------------------- +// Library used to check init/fini call order +// ----------------------------------------------------------------------------- +cc_test_library { + name: "libtest_init_fini_order_root", + defaults: ["bionic_testlib_defaults"], + srcs: ["dlopen_check_init_fini_root.cpp"], + shared_libs: ["libtest_init_fini_order_child"], +} + +cc_test_library { + name: "libtest_init_fini_order_child", + defaults: ["bionic_testlib_defaults"], + srcs: ["dlopen_check_init_fini_child.cpp"], + shared_libs: ["libtest_init_fini_order_grand_child"], +} + +cc_test_library { + name: "libtest_init_fini_order_grand_child", + defaults: ["bionic_testlib_defaults"], + srcs: ["dlopen_check_init_fini_grand_child.cpp"], +} + +// ----------------------------------------------------------------------------- // Library that depends on the library with constructor that calls dlopen() b/7941716 // ----------------------------------------------------------------------------- cc_test_library { diff --git a/tests/libs/dlopen_check_init_fini_child.cpp b/tests/libs/dlopen_check_init_fini_child.cpp new file mode 100644 index 000000000..bdb5f0690 --- /dev/null +++ b/tests/libs/dlopen_check_init_fini_child.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 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. + */ +#include <string> + +// These two function are called by local group's constructors and destructors +extern "C" __attribute__((weak)) void record_init(int digit); +extern "C" __attribute__((weak)) void record_fini(const char* s); + +static void __attribute__((constructor)) init() { + record_init(2); +} + +static void __attribute__((destructor)) fini() { + record_fini("(child)"); +} diff --git a/tests/libs/dlopen_check_init_fini_grand_child.cpp b/tests/libs/dlopen_check_init_fini_grand_child.cpp new file mode 100644 index 000000000..7900f3904 --- /dev/null +++ b/tests/libs/dlopen_check_init_fini_grand_child.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 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. + */ +#include <string> + +// These two function are called by local group's constructors and destructors +extern "C" __attribute__((weak)) void record_init(int digit); +extern "C" __attribute__((weak)) void record_fini(const char* s); + +static void __attribute__((constructor)) init() { + record_init(3); +} + +static void __attribute__((destructor)) fini() { + record_fini("(grandchild)"); +} diff --git a/tests/libs/dlopen_check_init_fini_root.cpp b/tests/libs/dlopen_check_init_fini_root.cpp new file mode 100644 index 000000000..45394ec46 --- /dev/null +++ b/tests/libs/dlopen_check_init_fini_root.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 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. + */ +#include <string> + +static int volatile g_initialization_order_code; + +void (*g_fini_callback)(const char*) = nullptr; + +// These two function are called by local group's constructors and destructors +extern "C" void record_init(int digit) { + g_initialization_order_code = g_initialization_order_code*10 + digit; +} + +extern "C" void record_fini(const char* s) { + g_fini_callback(s); +} + +// these 2 functions are used by the test +extern "C" int get_init_order_number() { + return g_initialization_order_code; +} + +extern "C" void set_fini_callback(void (*f)(const char*)) { + g_fini_callback = f; +} + +static void __attribute__((constructor)) init() { + record_init(1); +} + +static void __attribute__((destructor)) fini() { + record_fini("(root)"); +} |