xhwang | 6a01b39 | 2015-11-10 07:48:30 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/files/file_path.h" |
rockot | 596a0dd | 2016-08-26 00:57:51 | [diff] [blame] | 6 | #include "base/macros.h" |
xhwang | 6a01b39 | 2015-11-10 07:48:30 | [diff] [blame] | 7 | #include "base/native_library.h" |
rockot | 596a0dd | 2016-08-26 00:57:51 | [diff] [blame] | 8 | #include "base/path_service.h" |
| 9 | #include "base/test/native_library_test_utils.h" |
| 10 | #include "build/build_config.h" |
xhwang | 6a01b39 | 2015-11-10 07:48:30 | [diff] [blame] | 11 | #include "testing/gtest/include/gtest/gtest.h" |
| 12 | |
| 13 | namespace base { |
| 14 | |
| 15 | const FilePath::CharType kDummyLibraryPath[] = |
| 16 | FILE_PATH_LITERAL("dummy_library"); |
| 17 | |
| 18 | TEST(NativeLibraryTest, LoadFailure) { |
| 19 | NativeLibraryLoadError error; |
thestig | e38fbd6 | 2016-06-10 21:54:40 | [diff] [blame] | 20 | EXPECT_FALSE(LoadNativeLibrary(FilePath(kDummyLibraryPath), &error)); |
xhwang | 6a01b39 | 2015-11-10 07:48:30 | [diff] [blame] | 21 | EXPECT_FALSE(error.ToString().empty()); |
| 22 | } |
| 23 | |
| 24 | // |error| is optional and can be null. |
| 25 | TEST(NativeLibraryTest, LoadFailureWithNullError) { |
thestig | e38fbd6 | 2016-06-10 21:54:40 | [diff] [blame] | 26 | EXPECT_FALSE(LoadNativeLibrary(FilePath(kDummyLibraryPath), nullptr)); |
| 27 | } |
| 28 | |
| 29 | TEST(NativeLibraryTest, GetNativeLibraryName) { |
| 30 | const char kExpectedName[] = |
| 31 | #if defined(OS_IOS) |
| 32 | "mylib"; |
| 33 | #elif defined(OS_MACOSX) |
thestig | 02c965b | 2016-06-14 18:52:23 | [diff] [blame] | 34 | "libmylib.dylib"; |
thestig | e38fbd6 | 2016-06-10 21:54:40 | [diff] [blame] | 35 | #elif defined(OS_POSIX) |
| 36 | "libmylib.so"; |
| 37 | #elif defined(OS_WIN) |
| 38 | "mylib.dll"; |
| 39 | #endif |
thestig | 02c965b | 2016-06-14 18:52:23 | [diff] [blame] | 40 | EXPECT_EQ(kExpectedName, GetNativeLibraryName("mylib")); |
xhwang | 6a01b39 | 2015-11-10 07:48:30 | [diff] [blame] | 41 | } |
| 42 | |
rockot | 596a0dd | 2016-08-26 00:57:51 | [diff] [blame] | 43 | // We don't support dynamic loading on iOS, and ASAN will complain about our |
| 44 | // intentional ODR violation because of |g_native_library_exported_value| being |
| 45 | // defined globally both here and in the shared library. |
| 46 | #if !defined(OS_IOS) && !defined(ADDRESS_SANITIZER) |
| 47 | |
| 48 | const char kTestLibraryName[] = |
| 49 | #if defined(OS_MACOSX) |
| 50 | "libtest_shared_library.dylib"; |
| 51 | #elif defined(OS_ANDROID) && defined(COMPONENT_BUILD) |
| 52 | "libtest_shared_library.cr.so"; |
| 53 | #elif defined(OS_POSIX) |
| 54 | "libtest_shared_library.so"; |
| 55 | #elif defined(OS_WIN) |
| 56 | "test_shared_library.dll"; |
| 57 | #endif |
| 58 | |
| 59 | class TestLibrary { |
| 60 | public: |
| 61 | TestLibrary() : TestLibrary(NativeLibraryOptions()) {} |
| 62 | |
| 63 | explicit TestLibrary(const NativeLibraryOptions& options) |
| 64 | : library_(nullptr) { |
| 65 | base::FilePath exe_path; |
| 66 | CHECK(base::PathService::Get(base::DIR_EXE, &exe_path)); |
| 67 | |
| 68 | library_ = LoadNativeLibraryWithOptions( |
| 69 | exe_path.AppendASCII(kTestLibraryName), options, nullptr); |
| 70 | CHECK(library_); |
| 71 | } |
| 72 | |
| 73 | ~TestLibrary() { |
| 74 | UnloadNativeLibrary(library_); |
| 75 | } |
| 76 | |
| 77 | template <typename ReturnType, typename... Args> |
| 78 | ReturnType Call(const char* function_name, Args... args) { |
| 79 | return reinterpret_cast<ReturnType(*)(Args...)>( |
| 80 | GetFunctionPointerFromNativeLibrary(library_, function_name))(args...); |
| 81 | } |
| 82 | |
| 83 | private: |
| 84 | NativeLibrary library_; |
| 85 | |
| 86 | DISALLOW_COPY_AND_ASSIGN(TestLibrary); |
| 87 | }; |
| 88 | |
lizeb | 05b0a5f | 2016-08-26 12:51:31 | [diff] [blame] | 89 | // NativeLibraaryTest.LoadLibrary is failing on M tablets only. |
| 90 | // crbug/641309 |
| 91 | #if !defined(OS_ANDROID) |
| 92 | |
rockot | 596a0dd | 2016-08-26 00:57:51 | [diff] [blame] | 93 | // Verifies that we can load a native library and resolve its exported symbols. |
| 94 | TEST(NativeLibraryTest, LoadLibrary) { |
| 95 | TestLibrary library; |
| 96 | EXPECT_EQ(5, library.Call<int>("GetSimpleTestValue")); |
| 97 | } |
| 98 | |
lizeb | 05b0a5f | 2016-08-26 12:51:31 | [diff] [blame] | 99 | #endif // !defined(OS_ANDROID) |
| 100 | |
rockot | 596a0dd | 2016-08-26 00:57:51 | [diff] [blame] | 101 | // Android dlopen() requires further investigation, as it might vary across |
| 102 | // versions with respect to symbol resolution scope. |
avi | b0c09591 | 2017-03-31 01:24:12 | [diff] [blame] | 103 | // TSan and MSan error out on RTLD_DEEPBIND, https://crbug.com/705255 |
| 104 | #if !defined(OS_ANDROID) && !defined(THREAD_SANITIZER) && \ |
| 105 | !defined(MEMORY_SANITIZER) |
rockot | 596a0dd | 2016-08-26 00:57:51 | [diff] [blame] | 106 | |
| 107 | // Verifies that the |prefer_own_symbols| option satisfies its guarantee that |
| 108 | // a loaded library will always prefer local symbol resolution before |
| 109 | // considering global symbols. |
| 110 | TEST(NativeLibraryTest, LoadLibraryPreferOwnSymbols) { |
| 111 | NativeLibraryOptions options; |
| 112 | options.prefer_own_symbols = true; |
| 113 | TestLibrary library(options); |
| 114 | |
| 115 | // Verify that this binary and the DSO use different storage for |
| 116 | // |g_native_library_exported_value|. |
| 117 | g_native_library_exported_value = 1; |
| 118 | library.Call<void>("SetExportedValue", 2); |
| 119 | EXPECT_EQ(1, g_native_library_exported_value); |
| 120 | g_native_library_exported_value = 3; |
| 121 | EXPECT_EQ(2, library.Call<int>("GetExportedValue")); |
| 122 | |
| 123 | // Both this binary and the library link against the |
| 124 | // native_library_test_utils source library, which in turn exports the |
| 125 | // NativeLibraryTestIncrement() function whose return value depends on some |
| 126 | // static internal state. |
| 127 | // |
| 128 | // The DSO's GetIncrementValue() forwards to that function inside the DSO. |
| 129 | // |
| 130 | // Here we verify that direct calls to NativeLibraryTestIncrement() in this |
| 131 | // binary return a sequence of values independent from the sequence returned |
| 132 | // by GetIncrementValue(), ensuring that the DSO is calling its own local |
| 133 | // definition of NativeLibraryTestIncrement(). |
| 134 | EXPECT_EQ(1, library.Call<int>("GetIncrementValue")); |
| 135 | EXPECT_EQ(1, NativeLibraryTestIncrement()); |
| 136 | EXPECT_EQ(2, library.Call<int>("GetIncrementValue")); |
| 137 | EXPECT_EQ(3, library.Call<int>("GetIncrementValue")); |
| 138 | EXPECT_EQ(4, library.Call<int>("NativeLibraryTestIncrement")); |
| 139 | EXPECT_EQ(2, NativeLibraryTestIncrement()); |
| 140 | EXPECT_EQ(3, NativeLibraryTestIncrement()); |
| 141 | } |
| 142 | |
| 143 | #endif // !defined(OS_ANDROID) |
| 144 | |
| 145 | #endif // !defined(OS_IOS) && !defined(ADDRESS_SANITIZER) |
| 146 | |
xhwang | 6a01b39 | 2015-11-10 07:48:30 | [diff] [blame] | 147 | } // namespace base |