1 /*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <dlfcn.h>
17 #include <gtest/gtest.h>
18 #include "log.h"
19 #include "utils.h"
20 #include "libfs.h"
21 #include "KernelConstants.h"
22
23 using namespace testing::ext;
24
25 class DlopenTest : public testing::Test {
26 };
27
28 #define RES_DIR_DYLOAD RES_DIR_KERNEL "dyload/"
29 #define DYLOAD_TEST_DIR "/storage/data/"
30
31 /**
32 * @tc.number SUB_KERNEL_DL_SO_0100
33 * @tc.name the elf does not depend on any user-so, dlopen a full path so
34 * @tc.desc [C- SOFTWARE -0200]
35 */
HWTEST_F(DlopenTest, testDlopenFullPathSo, Function | MediumTest | Level1)36 HWTEST_F(DlopenTest, testDlopenFullPathSo, Function | MediumTest | Level1)
37 {
38 char* resSO = RES_DIR_DYLOAD "libdso1.so";
39 char* newSO = DYLOAD_TEST_DIR "libdso1.so";
40
41 // test SetUp
42 ASSERT_EQ(CopyFile(resSO, newSO), 0);
43 LOG("SetUp ok");
44
45 // test in child process
46 pid_t pid = fork();
47 ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
48 if (pid == 0) { // child
49 LOG("newSO: %s", newSO);
50 void* h = dlopen(newSO, RTLD_NOW);
51 if (!h) {
52 PANIC("dlopen %s failed: %s\n", newSO, dlerror());
53 }
54 LOG("dlopen '%s' ok", newSO);
55 int* i = (int*) dlsym(h, "g_int");
56 if (!i) {
57 PANIC("dlsym g_int failed: %s", dlerror());
58 }
59 if (*i != 1) {
60 PANIC("so initialization failed: want i=1 got i=%d", *i);
61 }
62
63 int (*f)(void) = (int (*)(void))dlsym(h, "inc_i");
64 if (!f) {
65 PANIC("dlsym func 'inc_i' failed: %s", dlerror());
66 }
67 f();
68 if (*i != 2) {
69 PANIC("inc_i call failed: want i=2 got i=%d", *i);
70 }
71 exit(0);
72 } else { // parent
73 Msleep(100);
74 WaitProcExitedOK(pid);
75 }
76
77 // test TearDown
78 ASSERT_EQ(RemoveFile(newSO), 0);
79 LOG("TearDown ok ");
80 }
81
82 /**
83 * @tc.number SUB_KERNEL_DL_SO_0200
84 * @tc.name the elf doesn't depend on any user-so, dlopen a relative-path so, twice
85 * @tc.desc [C- SOFTWARE -0200]
86 */
HWTEST_F(DlopenTest, testDlopenRelativePathSo, Function | MediumTest | Level1)87 HWTEST_F(DlopenTest, testDlopenRelativePathSo, Function | MediumTest | Level1)
88 {
89 char* resSO = RES_DIR_DYLOAD "libdso1.so";
90 char* testDir = DYLOAD_TEST_DIR "target";
91 char* testSo = DYLOAD_TEST_DIR "target/libdso1.so";
92 // test SetUp
93 char* curPath = GetCurrentPath();
94 ASSERT_NE(MakeDir(testDir), -1);
95 ASSERT_EQ(CopyFile(resSO, testSo), 0);
96 EXPECT_EQ(chdir(DYLOAD_TEST_DIR), 0);
97 LOG("SetUp ok");
98
99 // test in child process, so that this load-so will not effect other test
100 pid_t pid = fork();
101 ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
102 if (pid == 0) { // child
103 void* h = dlopen("./target/libdso1.so", RTLD_NOW);
104 if (!h) {
105 PANIC("dlopen './target/libdso1.so' failed: %s", dlerror());
106 }
107 int* i = (int*) dlsym(h, "g_int");
108 if (!i) {
109 PANIC("dlsym g_int failed: %s", dlerror());
110 }
111 if (*i != 1) {
112 PANIC("so initialization failed: want i=1 got i=%d", *i);
113 }
114 if (dlclose(h)) {
115 PANIC("dlclose failed: %s", dlerror());
116 }
117
118 void* g = dlopen("../data/target/libdso1.so", RTLD_NOW);
119 if (!g) {
120 PANIC("dlopen so again failed: %s", dlerror());
121 }
122 if (h != g) {
123 PANIC("dlopen same so return diff handle");
124 }
125 int (*f)(void) = (int (*)(void))dlsym(h, "inc_i");
126 if (!f) {
127 PANIC("dlsym func 'inc_i' failed: %s", dlerror());
128 }
129 f();
130 if (*i != 2) {
131 PANIC("inc_i call failed: want i=2 got i=%d", *i);
132 }
133 if (dlclose(h)) {
134 PANIC("dlclose failed: %s", dlerror());
135 }
136 LOG("Pass\n");
137 exit(0);
138 } else { // parent
139 Msleep(100);
140 WaitProcExitedOK(pid);
141 }
142
143 // test TearDown
144 EXPECT_EQ(chdir(curPath), 0);
145 ASSERT_EQ(RemoveFile(testSo), 0);
146 LOG("TearDown ok ");
147 }
148
149 /**
150 * @tc.number SUB_KERNEL_DL_SO_0400
151 * @tc.name the elf doesn't depend on any user-so. dlopen a not exist so.
152 * @tc.desc [C- SOFTWARE -0200]
153 */
HWTEST_F(DlopenTest, testDlopenNotExistSo, Function | MediumTest | Level3)154 HWTEST_F(DlopenTest, testDlopenNotExistSo, Function | MediumTest | Level3)
155 {
156 dlerror(); // clear any old error message
157 char* errMsg = dlerror();
158 if (errMsg) {
159 LOG("dlerror should return NULL when called twice.");
160 FAIL();
161 }
162
163 void* h = dlopen("not_exist_dso1.so", RTLD_NOW);
164 if (h) {
165 LOG("dlopen a non-exist-so should return NULL!");
166 FAIL();
167 }
168 errMsg = dlerror();
169 if (!errMsg) {
170 LOG("dlerror return NULL!");
171 FAIL();
172 }
173 char* p = strcasestr(errMsg, "No such file");
174 if (!p) {
175 LOG("dlerror msg invalid, should include 'No such file', actual msg=%s", errMsg);
176 FAIL();
177 }
178 }
179
180 /**
181 * @tc.number SUB_KERNEL_DL_SO_0500
182 * @tc.name the elf doesn't depend on any user-so, and dlopen continuously loads a same so
183 * @tc.desc [C- SOFTWARE -0200]
184 */
HWTEST_F(DlopenTest, testDlopenSameSo, Function | MediumTest | Level2)185 HWTEST_F(DlopenTest, testDlopenSameSo, Function | MediumTest | Level2)
186 {
187 char* resSO = RES_DIR_DYLOAD "libdso1.so";
188 char* newSO = DYLOAD_TEST_DIR "libdso1.so";
189
190 // test SetUp
191 ASSERT_EQ(CopyFile(resSO, newSO), 0);
192 LOG("SetUp ok");
193
194 // test in child process
195 pid_t pid = fork();
196 ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
197 if (pid == 0) { // child
198 void* h1 = dlopen(newSO, RTLD_NOW);
199 if (!h1) {
200 PANIC("dlopen %s failed: %s\n", newSO, dlerror());
201 }
202 void* h2 = dlopen(newSO, RTLD_NOW);
203 if (!h2) {
204 PANIC("dlopen %s failed: %s\n", newSO, dlerror());
205 }
206 if (h1 != h2) {
207 PANIC("dlopen same so return diff handle");
208 }
209 if (dlclose(h1)) {
210 PANIC("dlclose failed: %s", dlerror());
211 }
212 if (dlclose(h2)) {
213 PANIC("dlclose second handle failed: %s", dlerror());
214 }
215 exit(0);
216 } else { // parent
217 Msleep(100);
218 WaitProcExitedOK(pid);
219 }
220
221 // test TearDown
222 ASSERT_EQ(RemoveFile(newSO), 0);
223 LOG("TearDown ok ");
224 }
225
226 /**
227 * @tc.number SUB_KERNEL_DL_SO_0800
228 * @tc.name The tested elf depends on full-rpath so, and test same-symbol behaviour.
229 * and three so's have a same symbol
230 * @tc.desc [C- SOFTWARE -0200]
231 */
HWTEST_F(DlopenTest, testDlopenSameSymbolSo, Function | MediumTest | Level2)232 HWTEST_F(DlopenTest, testDlopenSameSymbolSo, Function | MediumTest | Level2)
233 {
234 char* testELF = RES_DIR_DYLOAD "dyload_rpath_full";
235 char* resSO1 = RES_DIR_DYLOAD "libdso1.so";
236 char* resSO2 = RES_DIR_DYLOAD "libdso2.so";
237 char* resSO3 = RES_DIR_DYLOAD "libdso3.so";
238 char* newSO1 = DYLOAD_TEST_DIR "libdso1.so";
239 char* newSO2 = DYLOAD_TEST_DIR "libdso2.so";
240 char* newSO3 = DYLOAD_TEST_DIR "libdso3.so";
241
242 // test SetUp
243 EXPECT_EQ(CopyFile(resSO1, newSO1), 0);
244 EXPECT_EQ(CopyFile(resSO2, newSO2), 0);
245 EXPECT_EQ(CopyFile(resSO3, newSO3), 0);
246 LOG("SetUp ok");
247
248 // test
249 int rt = RunElf(testELF, NULL, NULL);
250 EXPECT_EQ(rt, 0) << "same-symbol test failed! exitcode=" << rt;
251
252 // test TearDown
253 EXPECT_EQ(RemoveFile(newSO1), 0);
254 EXPECT_EQ(RemoveFile(newSO2), 0);
255 EXPECT_EQ(RemoveFile(newSO3), 0);
256 LOG("TearDown ok ");
257 }
258
259 /**
260 * @tc.number SUB_KERNEL_DL_SO_1000
261 * @tc.name the test elf compiled with rpath, and the depended-so is in that path
262 * @tc.desc [C- SOFTWARE -0200]
263 */
HWTEST_F(DlopenTest, testDlopenSoInRelativeRpath, Function | MediumTest | Level2)264 HWTEST_F(DlopenTest, testDlopenSoInRelativeRpath, Function | MediumTest | Level2)
265 {
266 char* testELF = RES_DIR_DYLOAD "dyload_rpath_relative";
267 char* resSO = RES_DIR_DYLOAD "libdso1.so";
268 char* newSO = "./lib/libdso1.so";
269
270 // test SetUp
271 ASSERT_NE(MakeDir("./lib"), -1);
272 ASSERT_EQ(CopyFile(resSO, newSO), 0);
273 LOG("SetUp ok");
274 Msleep(5000);
275
276 // test
277 int rt = RunElf(testELF, NULL, NULL);
278 EXPECT_EQ(rt, 0) << "dyload_rpath_relative failed! exitcode=" << rt;
279
280 // test TearDown
281 ASSERT_EQ(RemoveFile(newSO), 0);
282 LOG("TearDown ok ");
283 }
284
285