1 // Copyright 2015 The Chromium Authors
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/native_library.h"
6
7 #include "base/check.h"
8 #include "base/files/file_path.h"
9 #include "base/path_service.h"
10 #include "base/test/native_library_test_utils.h"
11 #include "build/build_config.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace base {
15
16 const FilePath::CharType kDummyLibraryPath[] =
17 FILE_PATH_LITERAL("dummy_library");
18
TEST(NativeLibraryTest,LoadFailure)19 TEST(NativeLibraryTest, LoadFailure) {
20 NativeLibraryLoadError error;
21 EXPECT_FALSE(LoadNativeLibrary(FilePath(kDummyLibraryPath), &error));
22 EXPECT_FALSE(error.ToString().empty());
23 }
24
25 // |error| is optional and can be null.
TEST(NativeLibraryTest,LoadFailureWithNullError)26 TEST(NativeLibraryTest, LoadFailureWithNullError) {
27 EXPECT_FALSE(LoadNativeLibrary(FilePath(kDummyLibraryPath), nullptr));
28 }
29
30 #if BUILDFLAG(IS_FUCHSIA)
TEST(NativeLibraryTest,LoadAbsolutePath)31 TEST(NativeLibraryTest, LoadAbsolutePath) {
32 EXPECT_TRUE(LoadNativeLibrary(FilePath("/pkg/lib/libtest_shared_library.so"),
33 nullptr));
34 }
35
TEST(NativeLibraryTest,LoadAbsolutePath_OutsideLibraryRoot)36 TEST(NativeLibraryTest, LoadAbsolutePath_OutsideLibraryRoot) {
37 NativeLibraryLoadError error;
38 EXPECT_FALSE(LoadNativeLibrary(FilePath("/pkg/tmp/libtest_shared_library.so"),
39 &error));
40 std::string expected_error =
41 "Absolute library paths must begin with /pkg/lib";
42 EXPECT_EQ(error.ToString(), expected_error);
43 }
44 #endif
45
TEST(NativeLibraryTest,GetNativeLibraryName)46 TEST(NativeLibraryTest, GetNativeLibraryName) {
47 const char kExpectedName[] =
48 #if BUILDFLAG(IS_WIN)
49 "mylib.dll";
50 #elif BUILDFLAG(IS_IOS)
51 "mylib";
52 #elif BUILDFLAG(IS_MAC)
53 "libmylib.dylib";
54 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
55 "libmylib.so";
56 #endif
57 EXPECT_EQ(kExpectedName, GetNativeLibraryName("mylib"));
58 }
59
TEST(NativeLibraryTest,GetLoadableModuleName)60 TEST(NativeLibraryTest, GetLoadableModuleName) {
61 const char kExpectedName[] =
62 #if BUILDFLAG(IS_WIN)
63 "mylib.dll";
64 #elif BUILDFLAG(IS_IOS)
65 "mylib";
66 #elif BUILDFLAG(IS_MAC)
67 "mylib.so";
68 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
69 "libmylib.so";
70 #endif
71 EXPECT_EQ(kExpectedName, GetLoadableModuleName("mylib"));
72 }
73
74 // We don't support dynamic loading on iOS, and ASAN will complain about our
75 // intentional ODR violation because of |g_native_library_exported_value| being
76 // defined globally both here and in the shared library.
77 #if !BUILDFLAG(IS_IOS) && !defined(ADDRESS_SANITIZER)
78
79 const char kTestLibraryName[] =
80 #if BUILDFLAG(IS_WIN)
81 "test_shared_library.dll";
82 #elif BUILDFLAG(IS_MAC)
83 "libtest_shared_library.dylib";
84 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
85 "libtest_shared_library.so";
86 #endif
87
88 class TestLibrary {
89 public:
TestLibrary()90 TestLibrary() : TestLibrary(NativeLibraryOptions()) {}
91
TestLibrary(const NativeLibraryOptions & options)92 explicit TestLibrary(const NativeLibraryOptions& options)
93 : library_(nullptr) {
94 base::FilePath exe_path;
95
96 #if !BUILDFLAG(IS_FUCHSIA)
97 // Libraries do not sit alongside the executable in Fuchsia. NativeLibrary
98 // is aware of this and is able to resolve library paths correctly.
99 CHECK(base::PathService::Get(base::DIR_EXE, &exe_path));
100 #endif
101
102 library_ = LoadNativeLibraryWithOptions(
103 exe_path.AppendASCII(kTestLibraryName), options, nullptr);
104 CHECK(library_);
105 }
106 TestLibrary(const TestLibrary&) = delete;
107 TestLibrary& operator=(const TestLibrary&) = delete;
~TestLibrary()108 ~TestLibrary() { UnloadNativeLibrary(library_); }
109
110 template <typename ReturnType, typename... Args>
Call(const char * function_name,Args...args)111 ReturnType Call(const char* function_name, Args... args) {
112 return reinterpret_cast<ReturnType (*)(Args...)>(
113 GetFunctionPointerFromNativeLibrary(library_, function_name))(args...);
114 }
115
116 private:
117 NativeLibrary library_;
118 };
119
120 // NativeLibraaryTest.LoadLibrary is failing on M tablets only.
121 // crbug/641309
122 #if !BUILDFLAG(IS_ANDROID)
123
124 // Verifies that we can load a native library and resolve its exported symbols.
TEST(NativeLibraryTest,LoadLibrary)125 TEST(NativeLibraryTest, LoadLibrary) {
126 TestLibrary library;
127 EXPECT_EQ(5, library.Call<int>("GetSimpleTestValue"));
128 }
129
130 #endif // !BUILDFLAG(IS_ANDROID)
131
132 // Android dlopen() requires further investigation, as it might vary across
133 // versions with respect to symbol resolution scope.
134 // TSan and MSan error out on RTLD_DEEPBIND, https://crbug.com/705255
135 #if !BUILDFLAG(IS_ANDROID) && !defined(THREAD_SANITIZER) && \
136 !defined(MEMORY_SANITIZER)
137
138 // Verifies that the |prefer_own_symbols| option satisfies its guarantee that
139 // a loaded library will always prefer local symbol resolution before
140 // considering global symbols.
TEST(NativeLibraryTest,LoadLibraryPreferOwnSymbols)141 TEST(NativeLibraryTest, LoadLibraryPreferOwnSymbols) {
142 NativeLibraryOptions options;
143 options.prefer_own_symbols = true;
144 TestLibrary library(options);
145
146 // Verify that this binary and the DSO use different storage for
147 // |g_native_library_exported_value|.
148 g_native_library_exported_value = 1;
149 library.Call<void>("SetExportedValue", 2);
150 EXPECT_EQ(1, g_native_library_exported_value);
151 g_native_library_exported_value = 3;
152 EXPECT_EQ(2, library.Call<int>("GetExportedValue"));
153
154 // Both this binary and the library link against the
155 // native_library_test_utils source library, which in turn exports the
156 // NativeLibraryTestIncrement() function whose return value depends on some
157 // static internal state.
158 //
159 // The DSO's GetIncrementValue() forwards to that function inside the DSO.
160 //
161 // Here we verify that direct calls to NativeLibraryTestIncrement() in this
162 // binary return a sequence of values independent from the sequence returned
163 // by GetIncrementValue(), ensuring that the DSO is calling its own local
164 // definition of NativeLibraryTestIncrement().
165 EXPECT_EQ(1, library.Call<int>("GetIncrementValue"));
166 EXPECT_EQ(1, NativeLibraryTestIncrement());
167 EXPECT_EQ(2, library.Call<int>("GetIncrementValue"));
168 EXPECT_EQ(3, library.Call<int>("GetIncrementValue"));
169 EXPECT_EQ(4, library.Call<int>("NativeLibraryTestIncrement"));
170 EXPECT_EQ(2, NativeLibraryTestIncrement());
171 EXPECT_EQ(3, NativeLibraryTestIncrement());
172 }
173
174 #endif // !BUILDFLAG(IS_ANDROID) && !defined(THREAD_SANITIZER) && \
175 // !defined(MEMORY_SANITIZER)
176
177 #endif // !BUILDFLAG(IS_IOS) && !defined(ADDRESS_SANITIZER)
178
179 } // namespace base
180