1 #include <dlfcn.h>
2 #include "test.h"
3
4 #define SO_FOR_NO_DELETE "lib_for_no_delete.so"
5 #define SO_FOR_DLOPEN "lib_for_dlopen.so"
6 #define SO_LOAD_BY_LOCAL "libdlopen_for_load_by_local_dso.so"
7 #define SO_LOAD_BY_GLOBAL "libdlopen_for_load_by_global_dso.so"
8 typedef void(*TEST_PTR)(void);
9
do_dlopen(const char * name,int mode)10 void do_dlopen(const char *name, int mode)
11 {
12 void* handle = dlopen(name, mode);
13
14 if(!handle)
15 t_error("dlopen(name=%s, mode=%d) failed: %s\n", name, mode, dlerror());
16
17 if(dlclose(handle))
18 t_error("dlclose %s failed : %s \n", name, dlerror());
19 }
20
dlopen_lazy()21 void dlopen_lazy()
22 {
23 do_dlopen(SO_FOR_DLOPEN, RTLD_LAZY);
24 }
25
dlopen_now()26 void dlopen_now()
27 {
28 do_dlopen(SO_FOR_DLOPEN, RTLD_NOW);
29 }
30
dlopen_global()31 void dlopen_global()
32 {
33 do_dlopen(SO_FOR_DLOPEN, RTLD_GLOBAL);
34 }
35
dlopen_local()36 void dlopen_local()
37 {
38 do_dlopen(SO_FOR_DLOPEN, RTLD_LOCAL);
39 }
40
dlopen_so_used_by_dlsym()41 void dlopen_so_used_by_dlsym()
42 {
43 void* handle1 = dlopen(SO_LOAD_BY_LOCAL, RTLD_LOCAL);
44 if(!handle1)
45 t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_LOAD_BY_LOCAL, RTLD_LOCAL, dlerror());
46
47 // dlsym can't see the so which is loaded by RTLD_LOCAL.
48 TEST_PTR for_local_ptr = dlsym(RTLD_DEFAULT, "for_local");
49 if (for_local_ptr != NULL) {
50 t_error("dlsym RTLD_LOCAL so(%s) should failed but get succeed.\n", "for_local");
51 }
52
53 if(dlclose(handle1))
54 t_error("dlclose %s failed : %s \n", SO_LOAD_BY_LOCAL, dlerror());
55
56
57 void* handle2 = dlopen(SO_LOAD_BY_GLOBAL, RTLD_GLOBAL);
58 if(!handle2)
59 t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_LOAD_BY_GLOBAL, RTLD_LOCAL, dlerror());
60
61 // dlsym can see the so which is loaded by RTLD_DEFAULT even without dependencies.
62 TEST_PTR for_global_ptr = dlsym(RTLD_DEFAULT, "for_global");
63 if (!for_global_ptr) {
64 t_error("dlsym RTLD_GLOBAL so(%s) should succeed but get failed: %s \n", "for_global", dlerror());
65 }
66
67 if(dlclose(handle2))
68 t_error("dlclose %s failed : %s \n", SO_LOAD_BY_GLOBAL, dlerror());
69 }
70
dlopen_nodelete_and_noload()71 void dlopen_nodelete_and_noload()
72 {
73 void* handle1 = dlopen(SO_FOR_NO_DELETE, RTLD_NODELETE);
74
75 if(!handle1)
76 t_error("dlopen(name=%s, mode=RTLD_NODELETE) failed: %s\n", SO_FOR_NO_DELETE, dlerror());
77
78 if(dlclose(handle1))
79 t_error("dlclose %s failed : %s \n", SO_FOR_NO_DELETE, dlerror());
80
81
82 void* handle2 = dlopen(SO_FOR_NO_DELETE, RTLD_NOLOAD);
83 if(!handle2)
84 t_error("dlopen(name=%s, mode=RTLD_NOLOAD) failed: %s\n", SO_FOR_NO_DELETE, dlerror());
85
86 if (handle1 != handle2) {
87 t_error("dlopen %s by RTLD_NODELETE but get different handle when dlopen by RTLD_NOLOAD again.\n", SO_FOR_NO_DELETE);
88 }
89 }
90
dlopen_dlclose()91 void dlopen_dlclose()
92 {
93 void* handle = dlopen(SO_FOR_DLOPEN, RTLD_LOCAL);
94 if(!handle)
95 t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror());
96
97 handle = dlopen(SO_FOR_DLOPEN, RTLD_LOCAL);
98 if(!handle)
99 t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror());
100
101 if(dlclose(handle))
102 t_error("dlclose %s failed : %s \n", SO_FOR_DLOPEN, dlerror());
103
104 // lib should still exist in memory.
105 handle = dlopen(SO_FOR_DLOPEN, RTLD_NOLOAD);
106 if(!handle)
107 t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror());
108
109 if(dlclose(handle))
110 t_error("dlclose %s failed : %s \n", SO_FOR_DLOPEN, dlerror());
111
112 // It need to do one more dlclose because call dlopen by RTLD_NOLOAD add reference counting.
113 if(dlclose(handle))
114 t_error("dlclose %s failed : %s \n", SO_FOR_DLOPEN, dlerror());
115
116 // dlopen and dlclose call counts match so the lib should not exist in memory.
117 handle = dlopen(SO_FOR_DLOPEN, RTLD_NOLOAD);
118 if(handle) {
119 t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror());
120 dlclose(handle);
121 }
122 }
123
main(int argc,char * argv[])124 int main(int argc, char *argv[])
125 {
126 void *h, *g;
127 int *i, *i2;
128 char *s;
129 void (*f)(void);
130 char buf[512];
131
132 if (!t_pathrel(buf, sizeof buf, argv[0], "libdlopen_dso.so")) {
133 t_error("failed to obtain relative path to dlopen_dso.so\n");
134 return 1;
135 }
136 h = dlopen(buf, RTLD_LAZY|RTLD_LOCAL);
137 if (!h)
138 t_error("dlopen %s failed: %s\n", buf, dlerror());
139 i = dlsym(h, "i");
140 if (!i)
141 t_error("dlsym i failed: %s\n", dlerror());
142 if (*i != 1)
143 t_error("initialization failed: want i=1 got i=%d\n", *i);
144 f = (void (*)(void))dlsym(h, "f");
145 if (!f)
146 t_error("dlsym f failed: %s\n", dlerror());
147 f();
148 if (*i != 2)
149 t_error("f call failed: want i=2 got i=%d\n", *i);
150
151 g = dlopen(0, RTLD_LAZY|RTLD_LOCAL);
152 if (!g)
153 t_error("dlopen 0 failed: %s\n", dlerror());
154 i2 = dlsym(g, "i");
155 s = dlerror();
156 if (i2 || s == 0)
157 t_error("dlsym i should have failed\n");
158 if (dlsym(g, "main") != (void*)main)
159 t_error("dlsym main failed: %s\n", dlerror());
160
161 /* close+open reinitializes the dso with glibc but not with musl */
162 h = dlopen(buf, RTLD_LAZY|RTLD_GLOBAL);
163 i2 = dlsym(g, "i");
164 if (!i2)
165 t_error("dlsym i failed: %s\n", dlerror());
166 if (i2 != i)
167 t_error("reopened dso should have the same symbols, want %p, got %p\n", i, i2);
168 if (*i2 != 2)
169 t_error("reopened dso should have the same symbols, want i2==2, got i2==%d\n", *i2);
170 if (dlclose(g))
171 t_error("dlclose failed: %s\n", dlerror());
172 if (dlclose(h))
173 t_error("dlclose failed: %s\n", dlerror());
174
175 dlopen_lazy();
176 dlopen_now();
177 dlopen_global();
178 dlopen_local();
179 dlopen_so_used_by_dlsym();
180 dlopen_nodelete_and_noload();
181 dlopen_dlclose();
182
183 return t_status;
184 }
185