1570af302Sopenharmony_ci/* 2570af302Sopenharmony_ci * Copyright (C) 2024 Huawei Device Co., Ltd. 3570af302Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4570af302Sopenharmony_ci * you may not use this file except in compliance with the License. 5570af302Sopenharmony_ci * You may obtain a copy of the License at 6570af302Sopenharmony_ci * 7570af302Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8570af302Sopenharmony_ci * 9570af302Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10570af302Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11570af302Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12570af302Sopenharmony_ci * See the License for the specific language governing permissions and 13570af302Sopenharmony_ci * limitations under the License. 14570af302Sopenharmony_ci */ 15570af302Sopenharmony_ci#include <dlfcn.h> 16570af302Sopenharmony_ci#include <pthread.h> 17570af302Sopenharmony_ci#include <stdio.h> 18570af302Sopenharmony_ci#include <string.h> 19570af302Sopenharmony_ci#include <stdlib.h> 20570af302Sopenharmony_ci#include <errno.h> 21570af302Sopenharmony_ci#include <link.h> 22570af302Sopenharmony_ci#include <sys/wait.h> 23570af302Sopenharmony_ci 24570af302Sopenharmony_ci#include "test.h" 25570af302Sopenharmony_ci 26570af302Sopenharmony_ci#define MAX_BUF 256 27570af302Sopenharmony_ci#define TEST_NUM 1000 28570af302Sopenharmony_ci#define TEST_SIZE 4096 29570af302Sopenharmony_ci 30570af302Sopenharmony_ciconst char* g_libPath = "/data/local/tmp/libc-test-lib/libdlopen_dso.so"; 31570af302Sopenharmony_ciconst char* g_initlibPath = "/data/local/tmp/libc-test-lib/libdlopen_init.so"; 32570af302Sopenharmony_civoid* g_init_handler = NULL; 33570af302Sopenharmony_cistatic int test_value = 0; 34570af302Sopenharmony_ci 35570af302Sopenharmony_ciint check_loaded(char* so) 36570af302Sopenharmony_ci{ 37570af302Sopenharmony_ci int pid = getpid(); 38570af302Sopenharmony_ci char path[MAX_BUF] = { 0 }; 39570af302Sopenharmony_ci sprintf(path, "/proc/%d/maps", pid); 40570af302Sopenharmony_ci FILE* fp = fopen(path, "r"); 41570af302Sopenharmony_ci if (fp == NULL) { 42570af302Sopenharmony_ci return 0; 43570af302Sopenharmony_ci } 44570af302Sopenharmony_ci 45570af302Sopenharmony_ci char buffer[MAX_BUF] = { 0 }; 46570af302Sopenharmony_ci while (fgets(buffer, MAX_BUF, fp) != NULL) { 47570af302Sopenharmony_ci if (strstr(buffer, so) != NULL) { 48570af302Sopenharmony_ci fclose(fp); 49570af302Sopenharmony_ci return 1; 50570af302Sopenharmony_ci } 51570af302Sopenharmony_ci } 52570af302Sopenharmony_ci fclose(fp); 53570af302Sopenharmony_ci return 0; 54570af302Sopenharmony_ci} 55570af302Sopenharmony_ci 56570af302Sopenharmony_cistatic int CallBack001(struct dl_phdr_info* info, size_t size, void* data) 57570af302Sopenharmony_ci{ 58570af302Sopenharmony_ci if (strcmp(info->dlpi_name, g_libPath) != 0 || strcmp(info->dlpi_name, g_initlibPath) != 0) { 59570af302Sopenharmony_ci return 0; 60570af302Sopenharmony_ci } 61570af302Sopenharmony_ci test_value++; 62570af302Sopenharmony_ci if (test_value != 1) { 63570af302Sopenharmony_ci t_error("test_value should be 1, but: %d\n", test_value); 64570af302Sopenharmony_ci } 65570af302Sopenharmony_ci test_value--; 66570af302Sopenharmony_ci 67570af302Sopenharmony_ci if (test_value != 0) { 68570af302Sopenharmony_ci t_error("test_value should be 0, but: %d\n", test_value); 69570af302Sopenharmony_ci } 70570af302Sopenharmony_ci return 0; 71570af302Sopenharmony_ci} 72570af302Sopenharmony_ci 73570af302Sopenharmony_cistatic int CallBack002(struct dl_phdr_info* info, size_t size, void* data) 74570af302Sopenharmony_ci{ 75570af302Sopenharmony_ci if (strcmp(info->dlpi_name, g_libPath) != 0 || strcmp(info->dlpi_name, g_initlibPath) != 0) { 76570af302Sopenharmony_ci return 0; 77570af302Sopenharmony_ci } 78570af302Sopenharmony_ci test_value = test_value + 2; 79570af302Sopenharmony_ci if (test_value != 2) { 80570af302Sopenharmony_ci t_error("test_value should be 2, but: %d\n", test_value); 81570af302Sopenharmony_ci } 82570af302Sopenharmony_ci 83570af302Sopenharmony_ci test_value = test_value - 2; 84570af302Sopenharmony_ci if (test_value != 0) { 85570af302Sopenharmony_ci t_error("test_value should be 0, but: %d\n", test_value); 86570af302Sopenharmony_ci } 87570af302Sopenharmony_ci return 0; 88570af302Sopenharmony_ci} 89570af302Sopenharmony_ci 90570af302Sopenharmony_cistatic void* CallBack003(void* arg) 91570af302Sopenharmony_ci{ 92570af302Sopenharmony_ci pid_t pid = fork(); 93570af302Sopenharmony_ci if (pid > 0) { 94570af302Sopenharmony_ci int status = 0; 95570af302Sopenharmony_ci int options = 0; 96570af302Sopenharmony_ci pid_t waitpid_for_pind = waitpid(pid, &status, options); 97570af302Sopenharmony_ci if (waitpid_for_pind != pid) { 98570af302Sopenharmony_ci t_error("%s waitpid get pid is %d are not want %d\n", __func__, waitpid_for_pind, pid); 99570af302Sopenharmony_ci } 100570af302Sopenharmony_ci if (status != 0) { 101570af302Sopenharmony_ci t_error("%s waitpid get status is %d are not 0\n", __func__, status); 102570af302Sopenharmony_ci } 103570af302Sopenharmony_ci } else if (pid == 0) { 104570af302Sopenharmony_ci sleep(1); 105570af302Sopenharmony_ci exit(0); 106570af302Sopenharmony_ci } else { 107570af302Sopenharmony_ci t_error("%s waitpid fork error\n"); 108570af302Sopenharmony_ci } 109570af302Sopenharmony_ci return arg; 110570af302Sopenharmony_ci} 111570af302Sopenharmony_ci 112570af302Sopenharmony_cistatic int CallBack004(struct dl_phdr_info* info, size_t size, void* data) 113570af302Sopenharmony_ci{ 114570af302Sopenharmony_ci char *memory = (char *)malloc(TEST_SIZE); 115570af302Sopenharmony_ci free(memory); 116570af302Sopenharmony_ci return 0; 117570af302Sopenharmony_ci} 118570af302Sopenharmony_ci 119570af302Sopenharmony_cistatic void* dlopen_dlclose_test001(void* arg) 120570af302Sopenharmony_ci{ 121570af302Sopenharmony_ci void* handle = dlopen(g_libPath, RTLD_NOW); 122570af302Sopenharmony_ci if (!handle) { 123570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", g_libPath, RTLD_NOW, dlerror()); 124570af302Sopenharmony_ci } 125570af302Sopenharmony_ci dlclose(handle); 126570af302Sopenharmony_ci return arg; 127570af302Sopenharmony_ci} 128570af302Sopenharmony_ci 129570af302Sopenharmony_cistatic void* dlopen_dlclose_test002(void* arg) 130570af302Sopenharmony_ci{ 131570af302Sopenharmony_ci void* handle = dlopen(g_initlibPath, RTLD_NOW); 132570af302Sopenharmony_ci if (!handle) { 133570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", g_initlibPath, RTLD_NOW, dlerror()); 134570af302Sopenharmony_ci } 135570af302Sopenharmony_ci g_init_handler = handle; 136570af302Sopenharmony_ci return arg; 137570af302Sopenharmony_ci} 138570af302Sopenharmony_ci 139570af302Sopenharmony_cistatic void* dlopen_dlclose_test003(void* arg) 140570af302Sopenharmony_ci{ 141570af302Sopenharmony_ci dlclose(g_init_handler); 142570af302Sopenharmony_ci return arg; 143570af302Sopenharmony_ci} 144570af302Sopenharmony_ci 145570af302Sopenharmony_cistatic void* dlopen_dlclose_test0041(void* arg) 146570af302Sopenharmony_ci{ 147570af302Sopenharmony_ci dl_iterate_phdr(CallBack001, NULL); 148570af302Sopenharmony_ci return arg; 149570af302Sopenharmony_ci} 150570af302Sopenharmony_ci 151570af302Sopenharmony_cistatic void* dlopen_dlclose_test0042(void* arg) 152570af302Sopenharmony_ci{ 153570af302Sopenharmony_ci dl_iterate_phdr(CallBack002, NULL); 154570af302Sopenharmony_ci return arg; 155570af302Sopenharmony_ci} 156570af302Sopenharmony_ci 157570af302Sopenharmony_cistatic void* dlopen_dlclose_test005(void* arg) 158570af302Sopenharmony_ci{ 159570af302Sopenharmony_ci int(* get_val)(void) = dlsym(g_init_handler, "getVal"); 160570af302Sopenharmony_ci if (get_val == NULL) { 161570af302Sopenharmony_ci t_error("dlsym failed, don't find the symbol getVal\n"); 162570af302Sopenharmony_ci } 163570af302Sopenharmony_ci if (get_val != NULL && get_val() != 1) { 164570af302Sopenharmony_ci t_error("This val after init should be 1, but %d\n", get_val()); 165570af302Sopenharmony_ci } 166570af302Sopenharmony_ci return arg; 167570af302Sopenharmony_ci} 168570af302Sopenharmony_ci 169570af302Sopenharmony_cistatic void* dlopen_dlclose_test006(void* arg) 170570af302Sopenharmony_ci{ 171570af302Sopenharmony_ci dl_iterate_phdr(CallBack004, NULL); 172570af302Sopenharmony_ci return arg; 173570af302Sopenharmony_ci} 174570af302Sopenharmony_ci 175570af302Sopenharmony_cistatic void do_test_concurrently(void *(*test) (void *arg), size_t num_threads) 176570af302Sopenharmony_ci{ 177570af302Sopenharmony_ci pthread_t *threads = (pthread_t *) malloc(sizeof(pthread_t) * num_threads); 178570af302Sopenharmony_ci if (threads == NULL) { 179570af302Sopenharmony_ci t_error("Failed to allocate memory: %s\n", strerror(errno)); 180570af302Sopenharmony_ci return; 181570af302Sopenharmony_ci } 182570af302Sopenharmony_ci 183570af302Sopenharmony_ci size_t last = 0; 184570af302Sopenharmony_ci while (last < num_threads) { 185570af302Sopenharmony_ci if (pthread_create(&(threads[last]), NULL, test, NULL)) { 186570af302Sopenharmony_ci t_error("Failed to create thread: %s\n", strerror(errno)); 187570af302Sopenharmony_ci break; 188570af302Sopenharmony_ci } 189570af302Sopenharmony_ci last++; 190570af302Sopenharmony_ci } 191570af302Sopenharmony_ci 192570af302Sopenharmony_ci for (size_t i = 0; i < last; i++) { 193570af302Sopenharmony_ci if (pthread_join(threads[i], NULL)) { 194570af302Sopenharmony_ci t_error("Failed to join thread: %s\n", strerror(errno)); 195570af302Sopenharmony_ci } 196570af302Sopenharmony_ci } 197570af302Sopenharmony_ci 198570af302Sopenharmony_ci free(threads); 199570af302Sopenharmony_ci return; 200570af302Sopenharmony_ci} 201570af302Sopenharmony_ci 202570af302Sopenharmony_cistatic void do_test_double_concurrently(void *(*test1) (void *arg), void *(*test2) (void *arg), 203570af302Sopenharmony_ci size_t num_threads1, size_t num_threads2) 204570af302Sopenharmony_ci{ 205570af302Sopenharmony_ci pthread_t *threads = (pthread_t *) malloc(sizeof(pthread_t) * (num_threads1 + num_threads2)); 206570af302Sopenharmony_ci if (threads == NULL) { 207570af302Sopenharmony_ci t_error("Failed to allocate memory: %s\n", strerror(errno)); 208570af302Sopenharmony_ci return; 209570af302Sopenharmony_ci } 210570af302Sopenharmony_ci 211570af302Sopenharmony_ci size_t last = 0; 212570af302Sopenharmony_ci while (last < num_threads1) { 213570af302Sopenharmony_ci if (pthread_create(&(threads[last]), NULL, test1, NULL)) { 214570af302Sopenharmony_ci t_error("Failed to create thread: %s\n", strerror(errno)); 215570af302Sopenharmony_ci break; 216570af302Sopenharmony_ci } 217570af302Sopenharmony_ci last++; 218570af302Sopenharmony_ci } 219570af302Sopenharmony_ci 220570af302Sopenharmony_ci while (last < num_threads1 + num_threads2) { 221570af302Sopenharmony_ci if (pthread_create(&(threads[last]), NULL, test2, NULL)) { 222570af302Sopenharmony_ci t_error("Failed to create thread: %s\n", strerror(errno)); 223570af302Sopenharmony_ci break; 224570af302Sopenharmony_ci } 225570af302Sopenharmony_ci last++; 226570af302Sopenharmony_ci } 227570af302Sopenharmony_ci 228570af302Sopenharmony_ci for (size_t i = 0; i < last; i++) { 229570af302Sopenharmony_ci if (pthread_join(threads[i], NULL)) { 230570af302Sopenharmony_ci t_error("Failed to join thread: %s\n", strerror(errno)); 231570af302Sopenharmony_ci } 232570af302Sopenharmony_ci } 233570af302Sopenharmony_ci 234570af302Sopenharmony_ci free(threads); 235570af302Sopenharmony_ci return; 236570af302Sopenharmony_ci} 237570af302Sopenharmony_ci 238570af302Sopenharmony_ci/** 239570af302Sopenharmony_ci * @tc.name : dl_multithread_lock_0100 240570af302Sopenharmony_ci * @tc.desc : multithreaded dlopen/dlclose, at the end the expected so file should not be in memory. 241570af302Sopenharmony_ci * @tc.level : Level 0 242570af302Sopenharmony_ci */ 243570af302Sopenharmony_civoid dl_multithread_lock_0100(void) 244570af302Sopenharmony_ci{ 245570af302Sopenharmony_ci size_t num_threads = 1000; 246570af302Sopenharmony_ci do_test_concurrently(dlopen_dlclose_test001, num_threads); 247570af302Sopenharmony_ci if (check_loaded((char*)g_libPath)) { 248570af302Sopenharmony_ci t_error("This so file should not exist, %s\n", (char*)g_libPath); 249570af302Sopenharmony_ci } 250570af302Sopenharmony_ci} 251570af302Sopenharmony_ci 252570af302Sopenharmony_ci/** 253570af302Sopenharmony_ci * @tc.name : dl_multithread_lock_0200 254570af302Sopenharmony_ci * @tc.desc : multithreaded dlopen, the init constructor should be called only once. 255570af302Sopenharmony_ci * @tc.level : Level 0 256570af302Sopenharmony_ci */ 257570af302Sopenharmony_civoid dl_multithread_lock_0200(void) 258570af302Sopenharmony_ci{ 259570af302Sopenharmony_ci size_t num_threads = 20; 260570af302Sopenharmony_ci do_test_concurrently(dlopen_dlclose_test002, num_threads); 261570af302Sopenharmony_ci if (!check_loaded((char*)g_initlibPath)) { 262570af302Sopenharmony_ci t_error("This so file should exist, %s\n", (char*)g_initlibPath); 263570af302Sopenharmony_ci } 264570af302Sopenharmony_ci int(* get_val)(void) = dlsym(g_init_handler, "getVal"); 265570af302Sopenharmony_ci if (get_val == NULL) { 266570af302Sopenharmony_ci t_error("dlsym failed, don't find the symbol getVal\n"); 267570af302Sopenharmony_ci } 268570af302Sopenharmony_ci if (get_val != NULL && get_val() != 1) { 269570af302Sopenharmony_ci t_error("This val after init should be 1, but %d\n", get_val()); 270570af302Sopenharmony_ci } 271570af302Sopenharmony_ci} 272570af302Sopenharmony_ci 273570af302Sopenharmony_ci/** 274570af302Sopenharmony_ci * @tc.name : dl_multithread_lock_0300 275570af302Sopenharmony_ci * @tc.desc : multithreaded dlopen, the deconstructor should be called only at the last dlclose. 276570af302Sopenharmony_ci * @tc.level : Level 0 277570af302Sopenharmony_ci */ 278570af302Sopenharmony_civoid dl_multithread_lock_0300(void) 279570af302Sopenharmony_ci{ 280570af302Sopenharmony_ci size_t num_threads = 19; 281570af302Sopenharmony_ci do_test_concurrently(dlopen_dlclose_test003, num_threads); 282570af302Sopenharmony_ci if (!check_loaded((char*)g_initlibPath)) { 283570af302Sopenharmony_ci t_error("This so file should exist, %s\n", (char*)g_initlibPath); 284570af302Sopenharmony_ci } 285570af302Sopenharmony_ci int(* get_val)(void) = dlsym(g_init_handler, "getVal"); 286570af302Sopenharmony_ci if (get_val == NULL) { 287570af302Sopenharmony_ci t_error("dlsym failed, don't find the symbol getVal\n"); 288570af302Sopenharmony_ci } 289570af302Sopenharmony_ci if (get_val != NULL && get_val() != 1) { 290570af302Sopenharmony_ci t_error("This val after init should be 1, but %d\n", get_val()); 291570af302Sopenharmony_ci } 292570af302Sopenharmony_ci dlclose(g_init_handler); 293570af302Sopenharmony_ci if (check_loaded((char*)g_initlibPath)) { 294570af302Sopenharmony_ci t_error("This so file should not exist, %s\n", (char*)g_initlibPath); 295570af302Sopenharmony_ci } 296570af302Sopenharmony_ci} 297570af302Sopenharmony_ci 298570af302Sopenharmony_ci/** 299570af302Sopenharmony_ci * @tc.name : dl_multithread_lock_0400 300570af302Sopenharmony_ci * @tc.desc : multithreaded iterate Callback in dl_iterate_phdr, the static test_value should be thread safe. 301570af302Sopenharmony_ci * @tc.level : Level 0 302570af302Sopenharmony_ci */ 303570af302Sopenharmony_civoid dl_multithread_lock_0400(void) 304570af302Sopenharmony_ci{ 305570af302Sopenharmony_ci void* handle1 = dlopen(g_libPath, RTLD_NOW); 306570af302Sopenharmony_ci if (!handle1) { 307570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", g_libPath, RTLD_NOW, dlerror()); 308570af302Sopenharmony_ci } 309570af302Sopenharmony_ci 310570af302Sopenharmony_ci void* handle2 = dlopen(g_initlibPath, RTLD_NOW); 311570af302Sopenharmony_ci if (!handle2) { 312570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", g_initlibPath, RTLD_NOW, dlerror()); 313570af302Sopenharmony_ci } 314570af302Sopenharmony_ci 315570af302Sopenharmony_ci size_t num_threads = 5; 316570af302Sopenharmony_ci do_test_double_concurrently(dlopen_dlclose_test0041, dlopen_dlclose_test0042, num_threads, num_threads); 317570af302Sopenharmony_ci 318570af302Sopenharmony_ci dlclose(handle1); 319570af302Sopenharmony_ci dlclose(handle2); 320570af302Sopenharmony_ci if (check_loaded((char*)g_initlibPath) || check_loaded((char*)g_libPath)) { 321570af302Sopenharmony_ci t_error("These so files should not exist\n"); 322570af302Sopenharmony_ci } 323570af302Sopenharmony_ci} 324570af302Sopenharmony_ci 325570af302Sopenharmony_ci/** 326570af302Sopenharmony_ci * @tc.name : dl_multithread_lock_0500 327570af302Sopenharmony_ci * @tc.desc : multithreaded dlsym, dlsym should not be blocked by dlsym in other threads. 328570af302Sopenharmony_ci * @tc.level : Level 0 329570af302Sopenharmony_ci */ 330570af302Sopenharmony_civoid dl_multithread_lock_0500(void) 331570af302Sopenharmony_ci{ 332570af302Sopenharmony_ci void* handle = dlopen(g_initlibPath, RTLD_NOW); 333570af302Sopenharmony_ci if (!handle) { 334570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", g_initlibPath, RTLD_NOW, dlerror()); 335570af302Sopenharmony_ci } 336570af302Sopenharmony_ci 337570af302Sopenharmony_ci g_init_handler = handle; 338570af302Sopenharmony_ci size_t num_threads = 1000; 339570af302Sopenharmony_ci do_test_concurrently(dlopen_dlclose_test005, num_threads); 340570af302Sopenharmony_ci g_init_handler = NULL; 341570af302Sopenharmony_ci dlclose(handle); 342570af302Sopenharmony_ci} 343570af302Sopenharmony_ci 344570af302Sopenharmony_ci/** 345570af302Sopenharmony_ci * @tc.name : dl_multithread_lock_0600 346570af302Sopenharmony_ci * @tc.desc : malloc and fork in different threads to check that there is no ABBA deadlock 347570af302Sopenharmony_ci * (ld lock and jemalloc lock). 348570af302Sopenharmony_ci * @tc.level : Level 0 349570af302Sopenharmony_ci */ 350570af302Sopenharmony_civoid dl_multithread_lock_0600(void) 351570af302Sopenharmony_ci{ 352570af302Sopenharmony_ci size_t num_threads = 100; 353570af302Sopenharmony_ci do_test_double_concurrently(dlopen_dlclose_test006, CallBack003, num_threads, num_threads); 354570af302Sopenharmony_ci} 355570af302Sopenharmony_ci 356570af302Sopenharmony_ciint main(int argc, char* argv[]) 357570af302Sopenharmony_ci{ 358570af302Sopenharmony_ci dl_multithread_lock_0100(); 359570af302Sopenharmony_ci dl_multithread_lock_0200(); 360570af302Sopenharmony_ci dl_multithread_lock_0300(); 361570af302Sopenharmony_ci dl_multithread_lock_0400(); 362570af302Sopenharmony_ci dl_multithread_lock_0500(); 363570af302Sopenharmony_ci dl_multithread_lock_0600(); 364570af302Sopenharmony_ci return t_status; 365570af302Sopenharmony_ci}