1 //! Dynamic library facilities.
3 //! A simple wrapper over the platform's dynamic library facilities
8 pub struct DynamicLibrary {
12 impl Drop for DynamicLibrary {
14 unsafe { dl::close(self.handle) }
19 /// Lazily open a dynamic library. When passed None it gives a
20 /// handle to the calling process
21 pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
22 let maybe_library = dl::open(filename.map(|path| path.as_os_str()));
24 // The dynamic library must not be constructed if there is
25 // an error opening the library so the destructor does not
29 Ok(handle) => Ok(DynamicLibrary { handle }),
33 /// Accesses the value at the symbol of the dynamic library.
34 pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
35 // This function should have a lifetime constraint of 'a on
36 // T but that feature is still unimplemented
38 let raw_string = CString::new(symbol).unwrap();
39 let maybe_symbol_value = dl::symbol(self.handle, raw_string.as_ptr());
41 // The value must not be constructed if there is an error so
42 // the destructor does not run.
43 match maybe_symbol_value {
45 Ok(symbol_value) => Ok(symbol_value as *mut T),
55 use std::ffi::{CStr, CString, OsStr};
56 use std::os::unix::prelude::*;
60 pub(super) fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
61 check_for_errors_in(|| unsafe {
63 Some(filename) => open_external(filename),
64 None => open_internal(),
69 unsafe fn open_external(filename: &OsStr) -> *mut u8 {
70 let s = CString::new(filename.as_bytes()).unwrap();
71 libc::dlopen(s.as_ptr(), libc::RTLD_LAZY) as *mut u8
74 unsafe fn open_internal() -> *mut u8 {
75 libc::dlopen(ptr::null(), libc::RTLD_LAZY) as *mut u8
78 fn check_for_errors_in<T, F>(f: F) -> Result<T, String>
82 use std::sync::{Mutex, Once};
83 static INIT: Once = Once::new();
84 static mut LOCK: *mut Mutex<()> = ptr::null_mut();
87 LOCK = Box::into_raw(Box::new(Mutex::new(())));
89 // dlerror isn't thread safe, so we need to lock around this entire
91 let _guard = (*LOCK).lock();
92 let _old_error = libc::dlerror();
96 let last_error = libc::dlerror() as *const _;
97 let ret = if ptr::null() == last_error {
100 let s = CStr::from_ptr(last_error).to_bytes();
101 Err(str::from_utf8(s).unwrap().to_owned())
108 pub(super) unsafe fn symbol(
110 symbol: *const libc::c_char,
111 ) -> Result<*mut u8, String> {
112 check_for_errors_in(|| libc::dlsym(handle as *mut libc::c_void, symbol) as *mut u8)
115 pub(super) unsafe fn close(handle: *mut u8) {
116 libc::dlclose(handle as *mut libc::c_void);
124 use std::os::windows::prelude::*;
127 use winapi::shared::minwindef::HMODULE;
128 use winapi::um::errhandlingapi::SetThreadErrorMode;
129 use winapi::um::libloaderapi::{FreeLibrary, GetModuleHandleExW, GetProcAddress, LoadLibraryW};
130 use winapi::um::winbase::SEM_FAILCRITICALERRORS;
132 pub(super) fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
133 // disable "dll load failed" error dialog.
134 let prev_error_mode = unsafe {
135 let new_error_mode = SEM_FAILCRITICALERRORS;
136 let mut prev_error_mode = 0;
137 let result = SetThreadErrorMode(new_error_mode, &mut prev_error_mode);
139 return Err(io::Error::last_os_error().to_string());
144 let result = match filename {
146 let filename_str: Vec<_> = filename.encode_wide().chain(Some(0)).collect();
147 let result = unsafe { LoadLibraryW(filename_str.as_ptr()) } as *mut u8;
151 let mut handle = ptr::null_mut();
152 let succeeded = unsafe { GetModuleHandleExW(0, ptr::null(), &mut handle) };
154 Err(io::Error::last_os_error().to_string())
156 Ok(handle as *mut u8)
162 SetThreadErrorMode(prev_error_mode, ptr::null_mut());
168 pub(super) unsafe fn symbol(
170 symbol: *const libc::c_char,
171 ) -> Result<*mut u8, String> {
172 let ptr = GetProcAddress(handle as HMODULE, symbol) as *mut u8;
176 pub(super) unsafe fn close(handle: *mut u8) {
177 FreeLibrary(handle as HMODULE);
180 fn ptr_result<T>(ptr: *mut T) -> Result<*mut T, String> {
181 if ptr.is_null() { Err(io::Error::last_os_error().to_string()) } else { Ok(ptr) }