dlopen.c 5.6 KB
Newer Older
M
maweiye 已提交
1 2 3
#include <dlfcn.h>
#include "test.h"

Y
yinchuang 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
#define SO_FOR_NO_DELETE "lib_for_no_delete.so"
#define SO_FOR_DLOPEN "lib_for_dlopen.so"
#define SO_LOAD_BY_LOCAL "libdlopen_for_load_by_local_dso.so"
#define SO_LOAD_BY_GLOBAL "libdlopen_for_load_by_global_dso.so"
typedef void(*TEST_PTR)(void);

void do_dlopen(const char *name, int mode)
{
	void* handle = dlopen(name, mode);

	if(!handle)
		t_error("dlopen(name=%s, mode=%d) failed: %s\n", name, mode, dlerror());

	if(dlclose(handle))
		t_error("dlclose %s failed : %s \n", name, dlerror());
}

void dlopen_lazy()
{
	do_dlopen(SO_FOR_DLOPEN, RTLD_LAZY);
}

void dlopen_now()
{
	do_dlopen(SO_FOR_DLOPEN, RTLD_NOW);
}

void dlopen_global()
{
	do_dlopen(SO_FOR_DLOPEN, RTLD_GLOBAL);
}

void dlopen_local()
{
	do_dlopen(SO_FOR_DLOPEN, RTLD_LOCAL);
}

void dlopen_so_used_by_dlsym()
{
	void* handle1 = dlopen(SO_LOAD_BY_LOCAL, RTLD_LOCAL);
	if(!handle1)
		t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_LOAD_BY_LOCAL, RTLD_LOCAL, dlerror());

	// dlsym can't see the so which is loaded by RTLD_LOCAL.
	TEST_PTR for_local_ptr = dlsym(RTLD_DEFAULT, "for_local");
	if (for_local_ptr != NULL) {
		t_error("dlsym RTLD_LOCAL so(%s) should failed but get succeed.\n", "for_local");
	}

	if(dlclose(handle1))
		t_error("dlclose %s failed : %s \n", SO_LOAD_BY_LOCAL, dlerror());


	void* handle2 = dlopen(SO_LOAD_BY_GLOBAL, RTLD_GLOBAL);
	if(!handle2)
		t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_LOAD_BY_GLOBAL, RTLD_LOCAL, dlerror());

	// dlsym can see the so which is loaded by RTLD_DEFAULT even without dependencies.
	TEST_PTR for_global_ptr = dlsym(RTLD_DEFAULT, "for_global");
	if (!for_global_ptr) {
		t_error("dlsym RTLD_GLOBAL so(%s) should succeed but get failed: %s \n", "for_global", dlerror());
	}

	if(dlclose(handle2))
		t_error("dlclose %s failed : %s \n", SO_LOAD_BY_GLOBAL, dlerror());
}

void dlopen_nodelete_and_noload()
{
	void* handle1 = dlopen(SO_FOR_NO_DELETE, RTLD_NODELETE);

	if(!handle1)
		t_error("dlopen(name=%s, mode=RTLD_NODELETE) failed: %s\n", SO_FOR_NO_DELETE, dlerror());

	if(dlclose(handle1))
		t_error("dlclose %s failed : %s \n", SO_FOR_NO_DELETE, dlerror());


	void* handle2 = dlopen(SO_FOR_NO_DELETE, RTLD_NOLOAD);
	if(!handle2)
		t_error("dlopen(name=%s, mode=RTLD_NOLOAD) failed: %s\n", SO_FOR_NO_DELETE, dlerror());

	if (handle1 != handle2) {
		t_error("dlopen %s by RTLD_NODELETE but get different handle when dlopen by RTLD_NOLOAD again.\n", SO_FOR_NO_DELETE);
	}
}

void dlopen_dlclose()
{
	void* handle = dlopen(SO_FOR_DLOPEN, RTLD_LOCAL);
	if(!handle)
		t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror());

	handle = dlopen(SO_FOR_DLOPEN, RTLD_LOCAL);
	if(!handle)
		t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror());

	if(dlclose(handle))
		t_error("dlclose %s failed : %s \n", SO_FOR_DLOPEN, dlerror());

	// lib should still exist in memory.
	handle = dlopen(SO_FOR_DLOPEN, RTLD_NOLOAD);
	if(!handle)
		t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror());

	if(dlclose(handle))
			t_error("dlclose %s failed : %s \n", SO_FOR_DLOPEN, dlerror());

	// It need to do one more dlclose because call dlopen by RTLD_NOLOAD add reference counting.
	if(dlclose(handle))
			t_error("dlclose %s failed : %s \n", SO_FOR_DLOPEN, dlerror());

	// dlopen and dlclose call counts match so the lib should not exist in memory.
	handle = dlopen(SO_FOR_DLOPEN, RTLD_NOLOAD);
	if(handle) {
		t_error("dlopen(name=%s, mode=%d) failed: %s\n", SO_FOR_DLOPEN, RTLD_LOCAL, dlerror());
		dlclose(handle);
	}
}

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
#define DLOPEN_WEAK "libdlopen_weak.so"
typedef int (*FuncPtr_TestNumber)(int input);

void dlopen_dlclose_weak()
{
	void* handle = dlopen(DLOPEN_WEAK, RTLD_LAZY | RTLD_GLOBAL);
	if (!handle)
		t_error("dlopen(name=%s, mode=%d) failed: %s\n", DLOPEN_WEAK, RTLD_LAZY | RTLD_GLOBAL, dlerror());
	FuncPtr_TestNumber fn = (FuncPtr_TestNumber)dlsym(handle, "TestNumber");
	if (fn) {
		int ret = fn(12);
		if (ret != 0)
			t_error("weak symbol relocation error: so_name: %s, symbol: TestNumber\n", DLOPEN_WEAK);
	}
	dlclose(handle);
}

M
maweiye 已提交
141 142 143 144 145 146 147 148
int main(int argc, char *argv[])
{
	void *h, *g;
	int *i, *i2;
	char *s;
	void (*f)(void);
	char buf[512];

M
maweiye 已提交
149
	if (!t_pathrel(buf, sizeof buf, argv[0], "libdlopen_dso.so")) {
M
maweiye 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
		t_error("failed to obtain relative path to dlopen_dso.so\n");
		return 1;
	}
	h = dlopen(buf, RTLD_LAZY|RTLD_LOCAL);
	if (!h)
		t_error("dlopen %s failed: %s\n", buf, dlerror());
	i = dlsym(h, "i");
	if (!i)
		t_error("dlsym i failed: %s\n", dlerror());
	if (*i != 1)
		t_error("initialization failed: want i=1 got i=%d\n", *i);
	f = (void (*)(void))dlsym(h, "f");
	if (!f)
		t_error("dlsym f failed: %s\n", dlerror());
	f();
	if (*i != 2)
		t_error("f call failed: want i=2 got i=%d\n", *i);

	g = dlopen(0, RTLD_LAZY|RTLD_LOCAL);
	if (!g)
		t_error("dlopen 0 failed: %s\n", dlerror());
	i2 = dlsym(g, "i");
	s = dlerror();
	if (i2 || s == 0)
		t_error("dlsym i should have failed\n");
	if (dlsym(g, "main") != (void*)main)
		t_error("dlsym main failed: %s\n", dlerror());

	/* close+open reinitializes the dso with glibc but not with musl */
	h = dlopen(buf, RTLD_LAZY|RTLD_GLOBAL);
	i2 = dlsym(g, "i");
	if (!i2)
		t_error("dlsym i failed: %s\n", dlerror());
	if (i2 != i)
		t_error("reopened dso should have the same symbols, want %p, got %p\n", i, i2);
	if (*i2 != 2)
		t_error("reopened dso should have the same symbols, want i2==2, got i2==%d\n", *i2);
M
maweiye 已提交
187
	if (dlclose(g))
M
maweiye 已提交
188 189 190
		t_error("dlclose failed: %s\n", dlerror());
	if (dlclose(h))
		t_error("dlclose failed: %s\n", dlerror());
Y
yinchuang 已提交
191 192 193 194 195 196 197 198

	dlopen_lazy();
	dlopen_now();
	dlopen_global();
	dlopen_local();
	dlopen_so_used_by_dlsym();
	dlopen_nodelete_and_noload();
	dlopen_dlclose();
199
	dlopen_dlclose_weak();
Y
yinchuang 已提交
200

M
maweiye 已提交
201 202
	return t_status;
}