1 import core.runtime;
2 import core.stdc.stdio;
3 import core.stdc.string;
4 import core.thread;
5 import core.sys.posix.dlfcn;
6 
7 version (DragonFlyBSD) import core.sys.dragonflybsd.dlfcn : RTLD_NOLOAD;
8 version (FreeBSD) import core.sys.freebsd.dlfcn : RTLD_NOLOAD;
9 version (linux) import core.sys.linux.dlfcn : RTLD_NOLOAD;
10 version (NetBSD) import core.sys.netbsd.dlfcn : RTLD_NOLOAD;
11 version (OSX) import core.sys.darwin.dlfcn : RTLD_NOLOAD;
12 version (Solaris) import core.sys.solaris.dlfcn : RTLD_NOLOAD;
13 
14 static assert(__traits(compiles, RTLD_NOLOAD), "unimplemented");
15 
loadSym(T)16 void loadSym(T)(void* handle, ref T val, const char* mangle)
17 {
18     val = cast(T).dlsym(handle, mangle);
19 }
20 
openLib(string s)21 void* openLib(string s)
22 {
23     auto h = Runtime.loadLibrary(s);
24     assert(h !is null);
25 
26     loadSym(h, libThrowException, "_D3lib14throwExceptionFZv");
27     loadSym(h, libCollectException, "_D3lib16collectExceptionFDFZvZC9Exception");
28 
29     loadSym(h, libAlloc, "_D3lib5allocFZv");
30     loadSym(h, libTlsAlloc, "_D3lib9tls_allocFZv");
31     loadSym(h, libAccess, "_D3lib6accessFZv");
32     loadSym(h, libTlsAccess, "_D3lib10tls_accessFZv");
33     loadSym(h, libFree, "_D3lib4freeFZv");
34     loadSym(h, libTlsFree, "_D3lib8tls_freeFZv");
35 
36     loadSym(h, libSharedStaticCtor, "_D3lib18shared_static_ctorOk");
37     loadSym(h, libSharedStaticDtor, "_D3lib18shared_static_dtorOk");
38     loadSym(h, libStaticCtor, "_D3lib11static_ctorOk");
39     loadSym(h, libStaticDtor, "_D3lib11static_dtorOk");
40 
41     return h;
42 }
43 
closeLib(void * h)44 void closeLib(void* h)
45 {
46     Runtime.unloadLibrary(h);
47 }
48 
49 __gshared
50 {
51     void function() libThrowException;
52     Exception function(void delegate()) libCollectException;
53 
54     void function() libAlloc;
55     void function() libTlsAlloc;
56     void function() libAccess;
57     void function() libTlsAccess;
58     void function() libFree;
59     void function() libTlsFree;
60 
61     shared uint* libSharedStaticCtor;
62     shared uint* libSharedStaticDtor;
63     shared uint* libStaticCtor;
64     shared uint* libStaticDtor;
65 }
66 
testEH()67 void testEH()
68 {
69     bool passed;
70     try
71         libThrowException();
72     catch (Exception e)
73         passed = true;
74     assert(passed); passed = false;
75 
76     assert(libCollectException({throw new Exception(null);}) !is null);
77     assert(libCollectException({libThrowException();}) !is null);
78 }
79 
testGC()80 void testGC()
81 {
82     import core.memory;
83     libAlloc();
84     libTlsAlloc();
85     libAccess();
86     libTlsAccess();
87     GC.collect();
88     libTlsAccess();
89     libAccess();
90     libTlsFree();
91     libFree();
92 }
93 
testInit()94 void testInit()
95 {
96 
97     assert(*libStaticCtor == 1);
98     assert(*libStaticDtor == 0);
99     static void run()
100     {
101         assert(*libSharedStaticCtor == 1);
102         assert(*libSharedStaticDtor == 0);
103         assert(*libStaticCtor == 2);
104         assert(*libStaticDtor == 0);
105     }
106     auto thr = new Thread(&run);
107     thr.start();
108     thr.join();
109     assert(*libSharedStaticCtor == 1);
110     assert(*libSharedStaticDtor == 0);
111     assert(*libStaticCtor == 2);
112     assert(*libStaticDtor == 1);
113 }
114 
findModuleInfo(string name)115 const(ModuleInfo)* findModuleInfo(string name)
116 {
117     foreach (m; ModuleInfo)
118         if (m.name == name) return m;
119     return null;
120 }
121 
runTests(string libName)122 void runTests(string libName)
123 {
124     assert(findModuleInfo("lib") is null);
125     auto handle = openLib(libName);
126     assert(findModuleInfo("lib") !is null);
127 
128     testEH();
129     testGC();
130     testInit();
131 
132     closeLib(handle);
133     assert(findModuleInfo("lib") is null);
134 }
135 
main(string[]args)136 void main(string[] args)
137 {
138     auto name = args[0] ~ '\0';
139     const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
140     name = name[0 .. pathlen] ~ "lib.so";
141 
142     runTests(name);
143 
144     // lib is no longer resident
145     name ~= '\0';
146     assert(.dlopen(name.ptr, RTLD_LAZY | RTLD_NOLOAD) is null);
147     name = name[0 .. $-1];
148 
149     auto thr = new Thread({runTests(name);});
150     thr.start();
151     thr.join();
152 }
153