• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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