1 #[cfg(windows)]
2 extern crate winapi;
3
4 extern crate libloading;
5 use libloading::{Symbol, Library};
6
7 const LIBPATH: &'static str = "target/libtest_helpers.module";
8
make_helpers()9 fn make_helpers() {
10 static ONCE: ::std::sync::Once = ::std::sync::Once::new();
11 ONCE.call_once(|| {
12 let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| { "rustc".into() });
13 let mut cmd = ::std::process::Command::new(rustc);
14 cmd
15 .arg("src/test_helpers.rs")
16 .arg("-o")
17 .arg(LIBPATH);
18 if let Some(target) = std::env::var_os("TARGET") {
19 cmd.arg("--target").arg(target);
20 } else {
21 eprintln!("WARNING: $TARGET NOT SPECIFIED! BUILDING HELPER MODULE FOR NATIVE TARGET.");
22 }
23 assert!(cmd
24 .status()
25 .expect("could not compile the test helpers!")
26 .success()
27 );
28 });
29 }
30
31 #[test]
test_id_u32()32 fn test_id_u32() {
33 make_helpers();
34 unsafe {
35 let lib = Library::new(LIBPATH).unwrap();
36 let f: Symbol<unsafe extern fn(u32) -> u32> = lib.get(b"test_identity_u32\0").unwrap();
37 assert_eq!(42, f(42));
38 }
39 }
40
41 #[repr(C)]
42 #[derive(Clone,Copy,PartialEq,Debug)]
43 struct S {
44 a: u64,
45 b: u32,
46 c: u16,
47 d: u8
48 }
49
50 #[test]
test_id_struct()51 fn test_id_struct() {
52 make_helpers();
53 unsafe {
54 let lib = Library::new(LIBPATH).unwrap();
55 let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
56 assert_eq!(S { a: 1, b: 2, c: 3, d: 4 }, f(S { a: 1, b: 2, c: 3, d: 4 }));
57 }
58 }
59
60 #[test]
test_0_no_0()61 fn test_0_no_0() {
62 make_helpers();
63 unsafe {
64 let lib = Library::new(LIBPATH).unwrap();
65 let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
66 let f2: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct").unwrap();
67 assert_eq!(*f, *f2);
68 }
69 }
70
71 #[test]
wrong_name_fails()72 fn wrong_name_fails() {
73 unsafe {
74 Library::new("target/this_location_is_definitely_non existent:^~").err().unwrap();
75 }
76 }
77
78 #[test]
missing_symbol_fails()79 fn missing_symbol_fails() {
80 make_helpers();
81 unsafe {
82 let lib = Library::new(LIBPATH).unwrap();
83 lib.get::<*mut ()>(b"test_does_not_exist").err().unwrap();
84 lib.get::<*mut ()>(b"test_does_not_exist\0").err().unwrap();
85 }
86 }
87
88 #[test]
interior_null_fails()89 fn interior_null_fails() {
90 make_helpers();
91 unsafe {
92 let lib = Library::new(LIBPATH).unwrap();
93 lib.get::<*mut ()>(b"test_does\0_not_exist").err().unwrap();
94 lib.get::<*mut ()>(b"test\0_does_not_exist\0").err().unwrap();
95 }
96 }
97
98 #[test]
test_incompatible_type()99 fn test_incompatible_type() {
100 make_helpers();
101 unsafe {
102 let lib = Library::new(LIBPATH).unwrap();
103 assert!(match lib.get::<()>(b"test_identity_u32\0") {
104 Err(libloading::Error::IncompatibleSize) => true,
105 _ => false,
106 })
107 }
108 }
109
110 #[test]
test_incompatible_type_named_fn()111 fn test_incompatible_type_named_fn() {
112 make_helpers();
113 unsafe fn get<'a, T>(l: &'a Library, _: T) -> Result<Symbol<'a, T>, libloading::Error> {
114 l.get::<T>(b"test_identity_u32\0")
115 }
116 unsafe {
117 let lib = Library::new(LIBPATH).unwrap();
118 assert!(match get(&lib, test_incompatible_type_named_fn) {
119 Err(libloading::Error::IncompatibleSize) => true,
120 _ => false,
121 })
122 }
123 }
124
125 #[test]
test_static_u32()126 fn test_static_u32() {
127 make_helpers();
128 unsafe {
129 let lib = Library::new(LIBPATH).unwrap();
130 let var: Symbol<*mut u32> = lib.get(b"TEST_STATIC_U32\0").unwrap();
131 **var = 42;
132 let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_static_u32\0").unwrap();
133 assert_eq!(42, help());
134 }
135 }
136
137 #[test]
test_static_ptr()138 fn test_static_ptr() {
139 make_helpers();
140 unsafe {
141 let lib = Library::new(LIBPATH).unwrap();
142 let var: Symbol<*mut *mut ()> = lib.get(b"TEST_STATIC_PTR\0").unwrap();
143 **var = *var as *mut _;
144 let works: Symbol<unsafe extern fn() -> bool> =
145 lib.get(b"test_check_static_ptr\0").unwrap();
146 assert!(works());
147 }
148 }
149
150 #[test]
151 // Something about i686-pc-windows-gnu, makes dll initialization code call abort when it is loaded
152 // and unloaded many times. So far it seems like an issue with mingw, not libloading, so ignoring
153 // the target. Especially since it is very unlikely to be fixed given the state of support its
154 // support.
155 #[cfg(not(all(target_arch="x86", target_os="windows", target_env="gnu")))]
manual_close_many_times()156 fn manual_close_many_times() {
157 make_helpers();
158 let join_handles: Vec<_> = (0..16).map(|_| {
159 std::thread::spawn(|| unsafe {
160 for _ in 0..10000 {
161 let lib = Library::new(LIBPATH).expect("open library");
162 let _: Symbol<unsafe extern fn(u32) -> u32> =
163 lib.get(b"test_identity_u32").expect("get fn");
164 lib.close().expect("close is successful");
165 }
166 })
167 }).collect();
168 for handle in join_handles {
169 handle.join().expect("thread should succeed");
170 }
171 }
172
173
174 #[cfg(unix)]
175 #[test]
library_this_get()176 fn library_this_get() {
177 use libloading::os::unix::Library;
178 make_helpers();
179 // SAFE: functions are never called
180 unsafe {
181 let _lib = Library::new(LIBPATH).unwrap();
182 let this = Library::this();
183 // Library we loaded in `_lib` (should be RTLD_LOCAL).
184 assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
185 // Something obscure from libc...
186 assert!(this.get::<unsafe extern "C" fn()>(b"freopen").is_ok());
187 }
188 }
189
190 #[cfg(windows)]
191 #[test]
library_this()192 fn library_this() {
193 use libloading::os::windows::Library;
194 make_helpers();
195 unsafe {
196 // SAFE: well-known library without initializers is loaded.
197 let _lib = Library::new(LIBPATH).unwrap();
198 let this = Library::this().expect("this library");
199 // SAFE: functions are never called.
200 // Library we loaded in `_lib`.
201 assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
202 // Something "obscure" from kernel32...
203 assert!(this.get::<unsafe extern "C" fn()>(b"GetLastError").is_err());
204 }
205 }
206
207 #[cfg(windows)]
208 #[test]
works_getlasterror()209 fn works_getlasterror() {
210 use winapi::um::errhandlingapi;
211 use winapi::shared::minwindef::DWORD;
212 use libloading::os::windows::{Library, Symbol};
213
214 unsafe {
215 let lib = Library::new("kernel32.dll").unwrap();
216 let gle: Symbol<unsafe extern "system" fn() -> DWORD> = lib.get(b"GetLastError").unwrap();
217 errhandlingapi::SetLastError(42);
218 assert_eq!(errhandlingapi::GetLastError(), gle())
219 }
220 }
221
222 #[cfg(windows)]
223 #[test]
works_getlasterror0()224 fn works_getlasterror0() {
225 use winapi::um::errhandlingapi;
226 use winapi::shared::minwindef::DWORD;
227 use libloading::os::windows::{Library, Symbol};
228
229 unsafe {
230 let lib = Library::new("kernel32.dll").unwrap();
231 let gle: Symbol<unsafe extern "system" fn() -> DWORD> = lib.get(b"GetLastError\0").unwrap();
232 errhandlingapi::SetLastError(42);
233 assert_eq!(errhandlingapi::GetLastError(), gle())
234 }
235 }
236
237 #[cfg(windows)]
238 #[test]
library_open_already_loaded()239 fn library_open_already_loaded() {
240 use libloading::os::windows::Library;
241
242 // Present on Windows systems and NOT used by any other tests to prevent races.
243 const LIBPATH: &str = "Msftedit.dll";
244
245 // Not loaded yet.
246 assert!(match Library::open_already_loaded(LIBPATH) {
247 Err(libloading::Error::GetModuleHandleExW { .. }) => true,
248 _ => false,
249 });
250
251 unsafe {
252 let _lib = Library::new(LIBPATH).unwrap();
253 // Loaded now.
254 assert!(Library::open_already_loaded(LIBPATH).is_ok());
255 }
256 }
257