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