Skip to content

Commit

Permalink
Simplify lib_path
Browse files Browse the repository at this point in the history
Since these are the tests, I'm sure we can afford to pay 1 allocation
per test for a path.
  • Loading branch information
nagisa committed Jan 18, 2022
1 parent 8009f51 commit 964dd8b
Showing 1 changed file with 63 additions and 52 deletions.
115 changes: 63 additions & 52 deletions tests/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,24 @@
extern crate winapi;

extern crate libloading;
use libloading::{Symbol, Library};
use libloading::{Library, Symbol};

const TARGET_DIR: Option<&'static str> = option_env!("CARGO_TARGET_DIR");
const TARGET_TMPDIR: Option<&'static str> = option_env!("CARGO_TARGET_TMPDIR");
static mut LIBPATH: String = String::new();

fn lib_path() -> &'static str {
static INIT: ::std::sync::Once = ::std::sync::Once::new();

unsafe {
INIT.call_once(|| {
LIBPATH = format!(
"{}/libtest_helpers.module",
TARGET_TMPDIR.unwrap_or(TARGET_DIR.unwrap_or("target"))
);
});
&LIBPATH
}
format!(
"{}/libtest_helpers.module",
TARGET_TMPDIR.unwrap_or(TARGET_DIR.unwrap_or("target"))
)
}

fn make_helpers() {
static ONCE: ::std::sync::Once = ::std::sync::Once::new();
ONCE.call_once(|| {
let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| { "rustc".into() });
let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
let mut cmd = ::std::process::Command::new(rustc);
cmd
.arg("src/test_helpers.rs")
.arg("-o")
.arg(lib_path());
cmd.arg("src/test_helpers.rs").arg("-o").arg(lib_path());
if let Some(target) = std::env::var_os("TARGET") {
cmd.arg("--target").arg(target);
} else {
Expand All @@ -39,8 +28,7 @@ fn make_helpers() {
assert!(cmd
.status()
.expect("could not compile the test helpers!")
.success()
);
.success());
});
}

Expand All @@ -49,27 +37,40 @@ fn test_id_u32() {
make_helpers();
unsafe {
let lib = Library::new(lib_path()).unwrap();
let f: Symbol<unsafe extern fn(u32) -> u32> = lib.get(b"test_identity_u32\0").unwrap();
let f: Symbol<unsafe extern "C" fn(u32) -> u32> = lib.get(b"test_identity_u32\0").unwrap();
assert_eq!(42, f(42));
}
}

#[repr(C)]
#[derive(Clone,Copy,PartialEq,Debug)]
#[derive(Clone, Copy, PartialEq, Debug)]
struct S {
a: u64,
b: u32,
c: u16,
d: u8
d: u8,
}

#[test]
fn test_id_struct() {
make_helpers();
unsafe {
let lib = Library::new(lib_path()).unwrap();
let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
assert_eq!(S { a: 1, b: 2, c: 3, d: 4 }, f(S { a: 1, b: 2, c: 3, d: 4 }));
let f: Symbol<unsafe extern "C" fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
assert_eq!(
S {
a: 1,
b: 2,
c: 3,
d: 4
},
f(S {
a: 1,
b: 2,
c: 3,
d: 4
})
);
}
}

Expand All @@ -78,16 +79,18 @@ fn test_0_no_0() {
make_helpers();
unsafe {
let lib = Library::new(lib_path()).unwrap();
let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
let f2: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct").unwrap();
let f: Symbol<unsafe extern "C" fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
let f2: Symbol<unsafe extern "C" fn(S) -> S> = lib.get(b"test_identity_struct").unwrap();
assert_eq!(*f, *f2);
}
}

#[test]
fn wrong_name_fails() {
unsafe {
Library::new("target/this_location_is_definitely_non existent:^~").err().unwrap();
Library::new("target/this_location_is_definitely_non existent:^~")
.err()
.unwrap();
}
}

Expand All @@ -107,7 +110,9 @@ fn interior_null_fails() {
unsafe {
let lib = Library::new(lib_path()).unwrap();
lib.get::<*mut ()>(b"test_does\0_not_exist").err().unwrap();
lib.get::<*mut ()>(b"test\0_does_not_exist\0").err().unwrap();
lib.get::<*mut ()>(b"test\0_does_not_exist\0")
.err()
.unwrap();
}
}

Expand All @@ -117,8 +122,8 @@ fn test_incompatible_type() {
unsafe {
let lib = Library::new(lib_path()).unwrap();
assert!(match lib.get::<()>(b"test_identity_u32\0") {
Err(libloading::Error::IncompatibleSize) => true,
_ => false,
Err(libloading::Error::IncompatibleSize) => true,
_ => false,
})
}
}
Expand All @@ -132,8 +137,8 @@ fn test_incompatible_type_named_fn() {
unsafe {
let lib = Library::new(lib_path()).unwrap();
assert!(match get(&lib, test_incompatible_type_named_fn) {
Err(libloading::Error::IncompatibleSize) => true,
_ => false,
Err(libloading::Error::IncompatibleSize) => true,
_ => false,
})
}
}
Expand All @@ -145,7 +150,8 @@ fn test_static_u32() {
let lib = Library::new(lib_path()).unwrap();
let var: Symbol<*mut u32> = lib.get(b"TEST_STATIC_U32\0").unwrap();
**var = 42;
let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_static_u32\0").unwrap();
let help: Symbol<unsafe extern "C" fn() -> u32> =
lib.get(b"test_get_static_u32\0").unwrap();
assert_eq!(42, help());
}
}
Expand All @@ -157,7 +163,7 @@ fn test_static_ptr() {
let lib = Library::new(lib_path()).unwrap();
let var: Symbol<*mut *mut ()> = lib.get(b"TEST_STATIC_PTR\0").unwrap();
**var = *var as *mut _;
let works: Symbol<unsafe extern fn() -> bool> =
let works: Symbol<unsafe extern "C" fn() -> bool> =
lib.get(b"test_check_static_ptr\0").unwrap();
assert!(works());
}
Expand All @@ -168,25 +174,26 @@ fn test_static_ptr() {
// and unloaded many times. So far it seems like an issue with mingw, not libloading, so ignoring
// the target. Especially since it is very unlikely to be fixed given the state of support its
// support.
#[cfg(not(all(target_arch="x86", target_os="windows", target_env="gnu")))]
#[cfg(not(all(target_arch = "x86", target_os = "windows", target_env = "gnu")))]
fn manual_close_many_times() {
make_helpers();
let join_handles: Vec<_> = (0..16).map(|_| {
std::thread::spawn(|| unsafe {
for _ in 0..10000 {
let lib = Library::new(lib_path()).expect("open library");
let _: Symbol<unsafe extern fn(u32) -> u32> =
lib.get(b"test_identity_u32").expect("get fn");
lib.close().expect("close is successful");
}
let join_handles: Vec<_> = (0..16)
.map(|_| {
std::thread::spawn(|| unsafe {
for _ in 0..10000 {
let lib = Library::new(lib_path()).expect("open library");
let _: Symbol<unsafe extern "C" fn(u32) -> u32> =
lib.get(b"test_identity_u32").expect("get fn");
lib.close().expect("close is successful");
}
})
})
}).collect();
.collect();
for handle in join_handles {
handle.join().expect("thread should succeed");
}
}


#[cfg(unix)]
#[test]
fn library_this_get() {
Expand All @@ -197,7 +204,9 @@ fn library_this_get() {
let _lib = Library::new(lib_path()).unwrap();
let this = Library::this();
// Library we loaded in `_lib` (should be RTLD_LOCAL).
assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
assert!(this
.get::<unsafe extern "C" fn()>(b"test_identity_u32")
.is_err());
// Something obscure from libc...
assert!(this.get::<unsafe extern "C" fn()>(b"freopen").is_ok());
}
Expand All @@ -214,7 +223,9 @@ fn library_this() {
let this = Library::this().expect("this library");
// SAFE: functions are never called.
// Library we loaded in `_lib`.
assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
assert!(this
.get::<unsafe extern "C" fn()>(b"test_identity_u32")
.is_err());
// Something "obscure" from kernel32...
assert!(this.get::<unsafe extern "C" fn()>(b"GetLastError").is_err());
}
Expand All @@ -223,9 +234,9 @@ fn library_this() {
#[cfg(windows)]
#[test]
fn works_getlasterror() {
use winapi::um::errhandlingapi;
use winapi::shared::minwindef::DWORD;
use libloading::os::windows::{Library, Symbol};
use winapi::shared::minwindef::DWORD;
use winapi::um::errhandlingapi;

unsafe {
let lib = Library::new("kernel32.dll").unwrap();
Expand All @@ -238,9 +249,9 @@ fn works_getlasterror() {
#[cfg(windows)]
#[test]
fn works_getlasterror0() {
use winapi::um::errhandlingapi;
use winapi::shared::minwindef::DWORD;
use libloading::os::windows::{Library, Symbol};
use winapi::shared::minwindef::DWORD;
use winapi::um::errhandlingapi;

unsafe {
let lib = Library::new("kernel32.dll").unwrap();
Expand Down

0 comments on commit 964dd8b

Please sign in to comment.