/* * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * 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 #include #include "log.h" #include "utils.h" #include "libfs.h" #include "KernelConstants.h" using namespace testing::ext; class DlopenTest : public testing::Test { }; #define RES_DIR_DYLOAD RES_DIR_KERNEL "dyload/" #define DYLOAD_TEST_DIR "/storage/data/" /** * @tc.number SUB_KERNEL_DL_SO_0100 * @tc.name the elf does not depend on any user-so, dlopen a full path so * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(DlopenTest, testDlopenFullPathSo, Function | MediumTest | Level1) { char* resSO = RES_DIR_DYLOAD "libdso1.so"; char* newSO = DYLOAD_TEST_DIR "libdso1.so"; // test SetUp ASSERT_EQ(CopyFile(resSO, newSO), 0); LOG("SetUp ok"); // test in child process pid_t pid = fork(); ASSERT_TRUE(pid >= 0) << "======== Fork Error! ========="; if (pid == 0) { // child LOG("newSO: %s", newSO); void* h = dlopen(newSO, RTLD_NOW); if (!h) { PANIC("dlopen %s failed: %s\n", newSO, dlerror()); } LOG("dlopen '%s' ok", newSO); int* i = (int*) dlsym(h, "g_int"); if (!i) { PANIC("dlsym g_int failed: %s", dlerror()); } if (*i != 1) { PANIC("so initialization failed: want i=1 got i=%d", *i); } int (*f)(void) = (int (*)(void))dlsym(h, "inc_i"); if (!f) { PANIC("dlsym func 'inc_i' failed: %s", dlerror()); } f(); if (*i != 2) { PANIC("inc_i call failed: want i=2 got i=%d", *i); } exit(0); } else { // parent Msleep(100); WaitProcExitedOK(pid); } // test TearDown ASSERT_EQ(RemoveFile(newSO), 0); LOG("TearDown ok "); } /** * @tc.number SUB_KERNEL_DL_SO_0200 * @tc.name the elf doesn't depend on any user-so, dlopen a relative-path so, twice * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(DlopenTest, testDlopenRelativePathSo, Function | MediumTest | Level1) { char* resSO = RES_DIR_DYLOAD "libdso1.so"; char* testDir = DYLOAD_TEST_DIR "target"; char* testSo = DYLOAD_TEST_DIR "target/libdso1.so"; // test SetUp char* curPath = GetCurrentPath(); ASSERT_NE(MakeDir(testDir), -1); ASSERT_EQ(CopyFile(resSO, testSo), 0); EXPECT_EQ(chdir(DYLOAD_TEST_DIR), 0); LOG("SetUp ok"); // test in child process, so that this load-so will not effect other test pid_t pid = fork(); ASSERT_TRUE(pid >= 0) << "======== Fork Error! ========="; if (pid == 0) { // child void* h = dlopen("./target/libdso1.so", RTLD_NOW); if (!h) { PANIC("dlopen './target/libdso1.so' failed: %s", dlerror()); } int* i = (int*) dlsym(h, "g_int"); if (!i) { PANIC("dlsym g_int failed: %s", dlerror()); } if (*i != 1) { PANIC("so initialization failed: want i=1 got i=%d", *i); } if (dlclose(h)) { PANIC("dlclose failed: %s", dlerror()); } void* g = dlopen("../data/target/libdso1.so", RTLD_NOW); if (!g) { PANIC("dlopen so again failed: %s", dlerror()); } if (h != g) { PANIC("dlopen same so return diff handle"); } int (*f)(void) = (int (*)(void))dlsym(h, "inc_i"); if (!f) { PANIC("dlsym func 'inc_i' failed: %s", dlerror()); } f(); if (*i != 2) { PANIC("inc_i call failed: want i=2 got i=%d", *i); } if (dlclose(h)) { PANIC("dlclose failed: %s", dlerror()); } LOG("Pass\n"); exit(0); } else { // parent Msleep(100); WaitProcExitedOK(pid); } // test TearDown EXPECT_EQ(chdir(curPath), 0); ASSERT_EQ(RemoveFile(testSo), 0); LOG("TearDown ok "); } /** * @tc.number SUB_KERNEL_DL_SO_0400 * @tc.name the elf doesn't depend on any user-so. dlopen a not exist so. * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(DlopenTest, testDlopenNotExistSo, Function | MediumTest | Level3) { dlerror(); // clear any old error message char* errMsg = dlerror(); if (errMsg) { LOG("dlerror should return NULL when called twice."); FAIL(); } void* h = dlopen("not_exist_dso1.so", RTLD_NOW); if (h) { LOG("dlopen a non-exist-so should return NULL!"); FAIL(); } errMsg = dlerror(); if (!errMsg) { LOG("dlerror return NULL!"); FAIL(); } char* p = strcasestr(errMsg, "No such file"); if (!p) { LOG("dlerror msg invalid, should include 'No such file', actual msg=%s", errMsg); FAIL(); } } /** * @tc.number SUB_KERNEL_DL_SO_0500 * @tc.name the elf doesn't depend on any user-so, and dlopen continuously loads a same so * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(DlopenTest, testDlopenSameSo, Function | MediumTest | Level2) { char* resSO = RES_DIR_DYLOAD "libdso1.so"; char* newSO = DYLOAD_TEST_DIR "libdso1.so"; // test SetUp ASSERT_EQ(CopyFile(resSO, newSO), 0); LOG("SetUp ok"); // test in child process pid_t pid = fork(); ASSERT_TRUE(pid >= 0) << "======== Fork Error! ========="; if (pid == 0) { // child void* h1 = dlopen(newSO, RTLD_NOW); if (!h1) { PANIC("dlopen %s failed: %s\n", newSO, dlerror()); } void* h2 = dlopen(newSO, RTLD_NOW); if (!h2) { PANIC("dlopen %s failed: %s\n", newSO, dlerror()); } if (h1 != h2) { PANIC("dlopen same so return diff handle"); } if (dlclose(h1)) { PANIC("dlclose failed: %s", dlerror()); } if (dlclose(h2)) { PANIC("dlclose second handle failed: %s", dlerror()); } exit(0); } else { // parent Msleep(100); WaitProcExitedOK(pid); } // test TearDown ASSERT_EQ(RemoveFile(newSO), 0); LOG("TearDown ok "); } /** * @tc.number SUB_KERNEL_DL_SO_0800 * @tc.name The tested elf depends on full-rpath so, and test same-symbol behaviour. * and three so's have a same symbol * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(DlopenTest, testDlopenSameSymbolSo, Function | MediumTest | Level2) { char* testELF = RES_DIR_DYLOAD "dyload_rpath_full"; char* resSO1 = RES_DIR_DYLOAD "libdso1.so"; char* resSO2 = RES_DIR_DYLOAD "libdso2.so"; char* resSO3 = RES_DIR_DYLOAD "libdso3.so"; char* newSO1 = DYLOAD_TEST_DIR "libdso1.so"; char* newSO2 = DYLOAD_TEST_DIR "libdso2.so"; char* newSO3 = DYLOAD_TEST_DIR "libdso3.so"; // test SetUp EXPECT_EQ(CopyFile(resSO1, newSO1), 0); EXPECT_EQ(CopyFile(resSO2, newSO2), 0); EXPECT_EQ(CopyFile(resSO3, newSO3), 0); LOG("SetUp ok"); // test int rt = RunElf(testELF, NULL, NULL); EXPECT_EQ(rt, 0) << "same-symbol test failed! exitcode=" << rt; // test TearDown EXPECT_EQ(RemoveFile(newSO1), 0); EXPECT_EQ(RemoveFile(newSO2), 0); EXPECT_EQ(RemoveFile(newSO3), 0); LOG("TearDown ok "); } /** * @tc.number SUB_KERNEL_DL_SO_1000 * @tc.name the test elf compiled with rpath, and the depended-so is in that path * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(DlopenTest, testDlopenSoInRelativeRpath, Function | MediumTest | Level2) { char* testELF = RES_DIR_DYLOAD "dyload_rpath_relative"; char* resSO = RES_DIR_DYLOAD "libdso1.so"; char* newSO = "./lib/libdso1.so"; // test SetUp ASSERT_NE(MakeDir("./lib"), -1); ASSERT_EQ(CopyFile(resSO, newSO), 0); LOG("SetUp ok"); Msleep(5000); // test int rt = RunElf(testELF, NULL, NULL); EXPECT_EQ(rt, 0) << "dyload_rpath_relative failed! exitcode=" << rt; // test TearDown ASSERT_EQ(RemoveFile(newSO), 0); LOG("TearDown ok "); }