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 initialisation 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 initialisers 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