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