1570af302Sopenharmony_ci#include <dlfcn.h> 2570af302Sopenharmony_ci#include <pthread.h> 3570af302Sopenharmony_ci#include <stdlib.h> 4570af302Sopenharmony_ci#include <sys/wait.h> 5570af302Sopenharmony_ci#include "test.h" 6570af302Sopenharmony_ci#include "global.h" 7570af302Sopenharmony_ci 8570af302Sopenharmony_ci#define SO_FOR_NO_DELETE "lib_for_no_delete.so" 9570af302Sopenharmony_ci#define SO_FOR_DLOPEN "lib_for_dlopen.so" 10570af302Sopenharmony_ci#define SO_LOAD_BY_LOCAL "libdlopen_for_load_by_local_dso.so" 11570af302Sopenharmony_ci#define SO_LOAD_BY_GLOBAL "libdlopen_for_load_by_global_dso.so" 12570af302Sopenharmony_ci#define SO_CLOSE_RECURSIVE_OPEN_SO "libdlclose_recursive_dlopen_so.so" 13570af302Sopenharmony_ci#define NR_DLCLOSE_THREADS 10 14570af302Sopenharmony_ci 15570af302Sopenharmony_citypedef void(*TEST_PTR)(void); 16570af302Sopenharmony_ci 17570af302Sopenharmony_civoid do_dlopen(const char *name, int mode) 18570af302Sopenharmony_ci{ 19570af302Sopenharmony_ci void* handle = dlopen(name, mode); 20570af302Sopenharmony_ci 21570af302Sopenharmony_ci if(!handle) 22570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", name, mode, dlerror()); 23570af302Sopenharmony_ci 24570af302Sopenharmony_ci if(dlclose(handle)) 25570af302Sopenharmony_ci t_error("dlclose %s failed : %s \n", name, dlerror()); 26570af302Sopenharmony_ci} 27570af302Sopenharmony_ci 28570af302Sopenharmony_civoid dlopen_lazy() 29570af302Sopenharmony_ci{ 30570af302Sopenharmony_ci do_dlopen(SO_FOR_DLOPEN, RTLD_LAZY); 31570af302Sopenharmony_ci} 32570af302Sopenharmony_ci 33570af302Sopenharmony_civoid dlopen_now() 34570af302Sopenharmony_ci{ 35570af302Sopenharmony_ci do_dlopen(SO_FOR_DLOPEN, RTLD_NOW); 36570af302Sopenharmony_ci} 37570af302Sopenharmony_ci 38570af302Sopenharmony_civoid dlopen_global() 39570af302Sopenharmony_ci{ 40570af302Sopenharmony_ci do_dlopen(SO_FOR_DLOPEN, RTLD_GLOBAL); 41570af302Sopenharmony_ci} 42570af302Sopenharmony_ci 43570af302Sopenharmony_civoid dlopen_local() 44570af302Sopenharmony_ci{ 45570af302Sopenharmony_ci do_dlopen(SO_FOR_DLOPEN, RTLD_LOCAL); 46570af302Sopenharmony_ci} 47570af302Sopenharmony_ci 48570af302Sopenharmony_civoid dlopen_so_used_by_dlsym() 49570af302Sopenharmony_ci{ 50570af302Sopenharmony_ci void* handle1 = dlopen(SO_LOAD_BY_LOCAL, RTLD_LOCAL); 51570af302Sopenharmony_ci if(!handle1) 52570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_LOAD_BY_LOCAL, RTLD_LOCAL, dlerror()); 53570af302Sopenharmony_ci 54570af302Sopenharmony_ci // dlsym can't see the so which is loaded by RTLD_LOCAL. 55570af302Sopenharmony_ci TEST_PTR for_local_ptr = dlsym(RTLD_DEFAULT, "for_local"); 56570af302Sopenharmony_ci if (for_local_ptr != NULL) { 57570af302Sopenharmony_ci t_error("dlsym RTLD_LOCAL so(%s) should failed but get succeed.\n", "for_local"); 58570af302Sopenharmony_ci } 59570af302Sopenharmony_ci 60570af302Sopenharmony_ci if(dlclose(handle1)) 61570af302Sopenharmony_ci t_error("dlclose %s failed : %s \n", SO_LOAD_BY_LOCAL, dlerror()); 62570af302Sopenharmony_ci 63570af302Sopenharmony_ci 64570af302Sopenharmony_ci void* handle2 = dlopen(SO_LOAD_BY_GLOBAL, RTLD_GLOBAL); 65570af302Sopenharmony_ci if(!handle2) 66570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_LOAD_BY_GLOBAL, RTLD_LOCAL, dlerror()); 67570af302Sopenharmony_ci 68570af302Sopenharmony_ci // dlsym can see the so which is loaded by RTLD_DEFAULT even without dependencies. 69570af302Sopenharmony_ci TEST_PTR for_global_ptr = dlsym(RTLD_DEFAULT, "for_global"); 70570af302Sopenharmony_ci if (!for_global_ptr) { 71570af302Sopenharmony_ci t_error("dlsym RTLD_GLOBAL so(%s) should succeed but get failed: %s \n", "for_global", dlerror()); 72570af302Sopenharmony_ci } 73570af302Sopenharmony_ci 74570af302Sopenharmony_ci if(dlclose(handle2)) 75570af302Sopenharmony_ci t_error("dlclose %s failed : %s \n", SO_LOAD_BY_GLOBAL, dlerror()); 76570af302Sopenharmony_ci} 77570af302Sopenharmony_ci 78570af302Sopenharmony_civoid dlopen_nodelete_and_noload() 79570af302Sopenharmony_ci{ 80570af302Sopenharmony_ci void* handle1 = dlopen(SO_FOR_NO_DELETE, RTLD_NODELETE); 81570af302Sopenharmony_ci 82570af302Sopenharmony_ci if(!handle1) 83570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=RTLD_NODELETE) failed: %s\n", SO_FOR_NO_DELETE, dlerror()); 84570af302Sopenharmony_ci 85570af302Sopenharmony_ci if(dlclose(handle1)) 86570af302Sopenharmony_ci t_error("dlclose %s failed : %s \n", SO_FOR_NO_DELETE, dlerror()); 87570af302Sopenharmony_ci 88570af302Sopenharmony_ci 89570af302Sopenharmony_ci void* handle2 = dlopen(SO_FOR_NO_DELETE, RTLD_NOLOAD); 90570af302Sopenharmony_ci if(!handle2) 91570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=RTLD_NOLOAD) failed: %s\n", SO_FOR_NO_DELETE, dlerror()); 92570af302Sopenharmony_ci 93570af302Sopenharmony_ci if (handle1 != handle2) { 94570af302Sopenharmony_ci t_error("dlopen %s by RTLD_NODELETE but get different handle when dlopen by RTLD_NOLOAD again.\n", SO_FOR_NO_DELETE); 95570af302Sopenharmony_ci } 96570af302Sopenharmony_ci} 97570af302Sopenharmony_ci 98570af302Sopenharmony_civoid dlopen_dlclose() 99570af302Sopenharmony_ci{ 100570af302Sopenharmony_ci void* handle = dlopen(SO_FOR_DLOPEN, RTLD_LOCAL); 101570af302Sopenharmony_ci if(!handle) 102570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror()); 103570af302Sopenharmony_ci 104570af302Sopenharmony_ci handle = dlopen(SO_FOR_DLOPEN, RTLD_LOCAL); 105570af302Sopenharmony_ci if(!handle) 106570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror()); 107570af302Sopenharmony_ci 108570af302Sopenharmony_ci if(dlclose(handle)) 109570af302Sopenharmony_ci t_error("dlclose %s failed : %s \n", SO_FOR_DLOPEN, dlerror()); 110570af302Sopenharmony_ci 111570af302Sopenharmony_ci // lib should still exist in memory. 112570af302Sopenharmony_ci handle = dlopen(SO_FOR_DLOPEN, RTLD_NOLOAD); 113570af302Sopenharmony_ci if(!handle) 114570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror()); 115570af302Sopenharmony_ci 116570af302Sopenharmony_ci if(dlclose(handle)) 117570af302Sopenharmony_ci t_error("dlclose %s failed : %s \n", SO_FOR_DLOPEN, dlerror()); 118570af302Sopenharmony_ci 119570af302Sopenharmony_ci // It need to do one more dlclose because call dlopen by RTLD_NOLOAD add reference counting. 120570af302Sopenharmony_ci if(dlclose(handle)) 121570af302Sopenharmony_ci t_error("dlclose %s failed : %s \n", SO_FOR_DLOPEN, dlerror()); 122570af302Sopenharmony_ci 123570af302Sopenharmony_ci // dlopen and dlclose call counts match so the lib should not exist in memory. 124570af302Sopenharmony_ci handle = dlopen(SO_FOR_DLOPEN, RTLD_NOLOAD); 125570af302Sopenharmony_ci if(handle) { 126570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror()); 127570af302Sopenharmony_ci dlclose(handle); 128570af302Sopenharmony_ci } 129570af302Sopenharmony_ci} 130570af302Sopenharmony_ci 131570af302Sopenharmony_ci#define DLOPEN_WEAK "libdlopen_weak.so" 132570af302Sopenharmony_citypedef int (*func_ptr)(); 133570af302Sopenharmony_ci 134570af302Sopenharmony_civoid dlopen_dlclose_weak() 135570af302Sopenharmony_ci{ 136570af302Sopenharmony_ci void* handle = dlopen(DLOPEN_WEAK, RTLD_LAZY | RTLD_GLOBAL); 137570af302Sopenharmony_ci if (!handle) 138570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", DLOPEN_WEAK, RTLD_LAZY | RTLD_GLOBAL, dlerror()); 139570af302Sopenharmony_ci func_ptr fn = (func_ptr)dlsym(handle, "test_number"); 140570af302Sopenharmony_ci if (fn) { 141570af302Sopenharmony_ci int ret = fn(); 142570af302Sopenharmony_ci if (ret != GLOBAL_VALUE) 143570af302Sopenharmony_ci t_error("weak symbol relocation error: so_name: %s, symbol: test_number\n", DLOPEN_WEAK); 144570af302Sopenharmony_ci } 145570af302Sopenharmony_ci dlclose(handle); 146570af302Sopenharmony_ci} 147570af302Sopenharmony_ci 148570af302Sopenharmony_civoid dlclose_recursive() 149570af302Sopenharmony_ci{ 150570af302Sopenharmony_ci void *handle = dlopen(SO_CLOSE_RECURSIVE_OPEN_SO, RTLD_LAZY | RTLD_LOCAL); 151570af302Sopenharmony_ci if (!handle) 152570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_CLOSE_RECURSIVE_OPEN_SO, RTLD_LAZY | RTLD_LOCAL, dlerror()); 153570af302Sopenharmony_ci 154570af302Sopenharmony_ci /* close handle normally, if libc doesn't support close .so file recursivly 155570af302Sopenharmony_ci * it will be deedlock, and timed out error will happen 156570af302Sopenharmony_ci */ 157570af302Sopenharmony_ci dlclose(handle); 158570af302Sopenharmony_ci} 159570af302Sopenharmony_ci 160570af302Sopenharmony_civoid *dlclose_recursive_thread() 161570af302Sopenharmony_ci{ 162570af302Sopenharmony_ci dlclose_recursive(); 163570af302Sopenharmony_ci return NULL; 164570af302Sopenharmony_ci} 165570af302Sopenharmony_ci 166570af302Sopenharmony_civoid dlclose_recursive_by_multipthread() 167570af302Sopenharmony_ci{ 168570af302Sopenharmony_ci pthread_t testThreads[NR_DLCLOSE_THREADS] = {0}; 169570af302Sopenharmony_ci for (int i = 0; i < NR_DLCLOSE_THREADS; ++i) { 170570af302Sopenharmony_ci pthread_create(&testThreads[i], NULL, dlclose_recursive_thread, NULL); 171570af302Sopenharmony_ci } 172570af302Sopenharmony_ci 173570af302Sopenharmony_ci for (int i = 0; i < NR_DLCLOSE_THREADS; ++i) { 174570af302Sopenharmony_ci pthread_join(testThreads[i], NULL); 175570af302Sopenharmony_ci } 176570af302Sopenharmony_ci} 177570af302Sopenharmony_ci 178570af302Sopenharmony_ci#define DLOPEN_GLOBAL "libdlopen_global.so" 179570af302Sopenharmony_ci#define DLOPEN_LOCAL "libdlopen_local.so" 180570af302Sopenharmony_ci 181570af302Sopenharmony_civoid dlopen_global_test() 182570af302Sopenharmony_ci{ 183570af302Sopenharmony_ci int value; 184570af302Sopenharmony_ci void *global_handler = dlopen(DLOPEN_GLOBAL, RTLD_GLOBAL); 185570af302Sopenharmony_ci if (!global_handler) 186570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", DLOPEN_GLOBAL, RTLD_GLOBAL, dlerror()); 187570af302Sopenharmony_ci func_ptr global_fn = (func_ptr)dlsym(global_handler, "global_caller"); 188570af302Sopenharmony_ci if (global_fn) { 189570af302Sopenharmony_ci value = global_fn(); 190570af302Sopenharmony_ci if (value != GLOBAL_VALUE) 191570af302Sopenharmony_ci t_error("global caller returned: %d, expected: %d\n", value, GLOBAL_VALUE); 192570af302Sopenharmony_ci } 193570af302Sopenharmony_ci 194570af302Sopenharmony_ci void *local_handler = dlopen(DLOPEN_LOCAL, RTLD_LOCAL); 195570af302Sopenharmony_ci if (!local_handler) 196570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", DLOPEN_LOCAL, RTLD_LOCAL, dlerror()); 197570af302Sopenharmony_ci func_ptr local_fn = (func_ptr)dlsym(local_handler, "local_caller"); 198570af302Sopenharmony_ci if (local_fn) { 199570af302Sopenharmony_ci value = local_fn(); 200570af302Sopenharmony_ci if (value != GLOBAL_VALUE) 201570af302Sopenharmony_ci t_error("local caller returned: %d, expected: %d\n", value, GLOBAL_VALUE); 202570af302Sopenharmony_ci } 203570af302Sopenharmony_ci dlclose(global_handler); 204570af302Sopenharmony_ci dlclose(local_handler); 205570af302Sopenharmony_ci} 206570af302Sopenharmony_ci 207570af302Sopenharmony_ci#define DLCLOSE_EXIT_DEAD_LOCK "libdl_multithread_test_dso.so" 208570af302Sopenharmony_ci 209570af302Sopenharmony_civoid dlclose_exit_test() 210570af302Sopenharmony_ci{ 211570af302Sopenharmony_ci int status; 212570af302Sopenharmony_ci void* handle; 213570af302Sopenharmony_ci int pid = fork(); 214570af302Sopenharmony_ci switch (pid) { 215570af302Sopenharmony_ci case -1: 216570af302Sopenharmony_ci t_error("fork failed: %d\n", __LINE__); 217570af302Sopenharmony_ci break; 218570af302Sopenharmony_ci case 0: 219570af302Sopenharmony_ci handle = dlopen(DLCLOSE_EXIT_DEAD_LOCK, RTLD_GLOBAL); 220570af302Sopenharmony_ci if (!handle) { 221570af302Sopenharmony_ci t_error("dlclose_exit_test dlopen %s failed: %s", DLCLOSE_EXIT_DEAD_LOCK, dlerror()); 222570af302Sopenharmony_ci exit(EXIT_FAILURE); 223570af302Sopenharmony_ci } 224570af302Sopenharmony_ci exit(EXIT_SUCCESS); 225570af302Sopenharmony_ci default: 226570af302Sopenharmony_ci waitpid(pid, &status, WUNTRACED); 227570af302Sopenharmony_ci if (WIFEXITED(status)) { 228570af302Sopenharmony_ci if (WEXITSTATUS(status) != EXIT_SUCCESS) { 229570af302Sopenharmony_ci t_error("dlclose_exit_test failed"); 230570af302Sopenharmony_ci }; 231570af302Sopenharmony_ci } 232570af302Sopenharmony_ci break; 233570af302Sopenharmony_ci } 234570af302Sopenharmony_ci return; 235570af302Sopenharmony_ci} 236570af302Sopenharmony_ci 237570af302Sopenharmony_ci#define DLCLOSE_WITH_TLS "libdlclose_tls.so" 238570af302Sopenharmony_citypedef void *(*functype)(void); 239570af302Sopenharmony_civoid dlclose_with_tls_test() 240570af302Sopenharmony_ci{ 241570af302Sopenharmony_ci void* handle = dlopen(DLCLOSE_WITH_TLS, RTLD_GLOBAL); 242570af302Sopenharmony_ci if (!handle) { 243570af302Sopenharmony_ci t_error("dlopen(name=%s, mode=%d) failed: %s\n", DLCLOSE_WITH_TLS, RTLD_GLOBAL, dlerror()); 244570af302Sopenharmony_ci } 245570af302Sopenharmony_ci functype func = (functype)dlsym(handle, "foo_ctor"); 246570af302Sopenharmony_ci func(); 247570af302Sopenharmony_ci dlclose(handle); 248570af302Sopenharmony_ci} 249570af302Sopenharmony_ci 250570af302Sopenharmony_ciint main(int argc, char *argv[]) 251570af302Sopenharmony_ci{ 252570af302Sopenharmony_ci void *h, *g; 253570af302Sopenharmony_ci int *i, *i2; 254570af302Sopenharmony_ci char *s; 255570af302Sopenharmony_ci void (*f)(void); 256570af302Sopenharmony_ci char buf[512]; 257570af302Sopenharmony_ci 258570af302Sopenharmony_ci if (!t_pathrel(buf, sizeof buf, argv[0], "libdlopen_dso.so")) { 259570af302Sopenharmony_ci t_error("failed to obtain relative path to dlopen_dso.so\n"); 260570af302Sopenharmony_ci return 1; 261570af302Sopenharmony_ci } 262570af302Sopenharmony_ci h = dlopen(buf, RTLD_LAZY|RTLD_LOCAL); 263570af302Sopenharmony_ci if (!h) 264570af302Sopenharmony_ci t_error("dlopen %s failed: %s\n", buf, dlerror()); 265570af302Sopenharmony_ci i = dlsym(h, "i"); 266570af302Sopenharmony_ci if (!i) 267570af302Sopenharmony_ci t_error("dlsym i failed: %s\n", dlerror()); 268570af302Sopenharmony_ci if (*i != 1) 269570af302Sopenharmony_ci t_error("initialization failed: want i=1 got i=%d\n", *i); 270570af302Sopenharmony_ci f = (void (*)(void))dlsym(h, "f"); 271570af302Sopenharmony_ci if (!f) 272570af302Sopenharmony_ci t_error("dlsym f failed: %s\n", dlerror()); 273570af302Sopenharmony_ci f(); 274570af302Sopenharmony_ci if (*i != 2) 275570af302Sopenharmony_ci t_error("f call failed: want i=2 got i=%d\n", *i); 276570af302Sopenharmony_ci 277570af302Sopenharmony_ci g = dlopen(0, RTLD_LAZY|RTLD_LOCAL); 278570af302Sopenharmony_ci if (!g) 279570af302Sopenharmony_ci t_error("dlopen 0 failed: %s\n", dlerror()); 280570af302Sopenharmony_ci i2 = dlsym(g, "i"); 281570af302Sopenharmony_ci s = dlerror(); 282570af302Sopenharmony_ci if (i2 || s == 0) 283570af302Sopenharmony_ci t_error("dlsym i should have failed\n"); 284570af302Sopenharmony_ci if (dlsym(g, "main") != (void*)main) 285570af302Sopenharmony_ci t_error("dlsym main failed: %s\n", dlerror()); 286570af302Sopenharmony_ci 287570af302Sopenharmony_ci /* close+open reinitializes the dso with glibc but not with musl */ 288570af302Sopenharmony_ci h = dlopen(buf, RTLD_LAZY|RTLD_GLOBAL); 289570af302Sopenharmony_ci i2 = dlsym(g, "i"); 290570af302Sopenharmony_ci if (!i2) 291570af302Sopenharmony_ci t_error("dlsym i failed: %s\n", dlerror()); 292570af302Sopenharmony_ci if (i2 != i) 293570af302Sopenharmony_ci t_error("reopened dso should have the same symbols, want %p, got %p\n", i, i2); 294570af302Sopenharmony_ci if (*i2 != 2) 295570af302Sopenharmony_ci t_error("reopened dso should have the same symbols, want i2==2, got i2==%d\n", *i2); 296570af302Sopenharmony_ci if (dlclose(g)) 297570af302Sopenharmony_ci t_error("dlclose failed: %s\n", dlerror()); 298570af302Sopenharmony_ci if (dlclose(h)) 299570af302Sopenharmony_ci t_error("dlclose failed: %s\n", dlerror()); 300570af302Sopenharmony_ci 301570af302Sopenharmony_ci dlopen_lazy(); 302570af302Sopenharmony_ci dlopen_now(); 303570af302Sopenharmony_ci dlopen_global(); 304570af302Sopenharmony_ci dlopen_local(); 305570af302Sopenharmony_ci dlopen_so_used_by_dlsym(); 306570af302Sopenharmony_ci dlopen_nodelete_and_noload(); 307570af302Sopenharmony_ci dlopen_dlclose(); 308570af302Sopenharmony_ci dlopen_dlclose_weak(); 309570af302Sopenharmony_ci dlclose_recursive(); 310570af302Sopenharmony_ci dlclose_recursive_by_multipthread(); 311570af302Sopenharmony_ci dlopen_global_test(); 312570af302Sopenharmony_ci dlclose_exit_test(); 313570af302Sopenharmony_ci dlclose_with_tls_test(); 314570af302Sopenharmony_ci 315570af302Sopenharmony_ci return t_status; 316570af302Sopenharmony_ci} 317