2014-11-25 21:17:11 -05:00
|
|
|
//! Dynamic library facilities.
|
|
|
|
//!
|
|
|
|
//! A simple wrapper over the platform's dynamic library facilities
|
2014-04-29 11:38:51 -07:00
|
|
|
|
2017-08-19 03:09:55 +03:00
|
|
|
use std::ffi::CString;
|
|
|
|
use std::path::Path;
|
2016-03-07 15:42:29 -08:00
|
|
|
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 17:01:33 -08:00
|
|
|
pub struct DynamicLibrary {
|
2019-12-22 17:42:04 -05:00
|
|
|
handle: *mut u8,
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 17:01:33 -08:00
|
|
|
}
|
2013-06-08 23:29:32 -07:00
|
|
|
|
|
|
|
impl Drop for DynamicLibrary {
|
2013-09-16 21:18:07 -04:00
|
|
|
fn drop(&mut self) {
|
2019-12-22 17:42:04 -05:00
|
|
|
unsafe { dl::close(self.handle) }
|
2013-06-08 23:29:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DynamicLibrary {
|
2020-04-24 18:31:42 -04:00
|
|
|
/// Lazily open a dynamic library.
|
|
|
|
pub fn open(filename: &Path) -> Result<DynamicLibrary, String> {
|
|
|
|
let maybe_library = dl::open(filename.as_os_str());
|
2015-01-10 22:53:22 +09:00
|
|
|
|
|
|
|
// The dynamic library must not be constructed if there is
|
|
|
|
// an error opening the library so the destructor does not
|
|
|
|
// run.
|
|
|
|
match maybe_library {
|
|
|
|
Err(err) => Err(err),
|
2019-12-22 17:42:04 -05:00
|
|
|
Ok(handle) => Ok(DynamicLibrary { handle }),
|
2018-01-22 07:29:24 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-13 10:21:32 -04:00
|
|
|
/// Accesses the value at the symbol of the dynamic library.
|
2014-06-25 12:47:34 -07:00
|
|
|
pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
|
2013-12-09 23:16:18 -08:00
|
|
|
// This function should have a lifetime constraint of 'a on
|
2013-06-08 23:29:32 -07:00
|
|
|
// T but that feature is still unimplemented
|
|
|
|
|
2015-02-17 22:47:40 -08:00
|
|
|
let raw_string = CString::new(symbol).unwrap();
|
2016-03-07 15:42:29 -08:00
|
|
|
let maybe_symbol_value = dl::symbol(self.handle, raw_string.as_ptr());
|
2013-06-08 23:29:32 -07:00
|
|
|
|
2013-08-01 14:58:37 -07:00
|
|
|
// The value must not be constructed if there is an error so
|
|
|
|
// the destructor does not run.
|
|
|
|
match maybe_symbol_value {
|
|
|
|
Err(err) => Err(err),
|
2019-12-22 17:42:04 -05:00
|
|
|
Ok(symbol_value) => Ok(symbol_value as *mut T),
|
2013-06-08 23:29:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-07 15:42:29 -08:00
|
|
|
#[cfg(test)]
|
2019-06-06 02:53:24 +09:00
|
|
|
mod tests;
|
2013-06-08 23:29:32 -07:00
|
|
|
|
2016-03-07 15:42:29 -08:00
|
|
|
#[cfg(unix)]
|
2015-01-10 22:53:22 +09:00
|
|
|
mod dl {
|
2020-08-20 14:34:40 -07:00
|
|
|
use std::ffi::{CString, OsStr};
|
2016-03-07 15:42:29 -08:00
|
|
|
use std::os::unix::prelude::*;
|
2013-06-08 23:29:32 -07:00
|
|
|
|
2020-08-25 12:02:21 -07:00
|
|
|
// As of the 2017 revision of the POSIX standard (IEEE 1003.1-2017), it is
|
|
|
|
// implementation-defined whether `dlerror` is thread-safe (in which case it returns the most
|
|
|
|
// recent error in the calling thread) or not thread-safe (in which case it returns the most
|
|
|
|
// recent error in *any* thread).
|
|
|
|
//
|
|
|
|
// There's no easy way to tell what strategy is used by a given POSIX implementation, so we
|
|
|
|
// lock around all calls that can modify `dlerror` in this module lest we accidentally read an
|
|
|
|
// error from a different thread. This is bulletproof when we are the *only* code using the
|
|
|
|
// dynamic library APIs at a given point in time. However, it's still possible for us to race
|
|
|
|
// with other code (see #74469) on platforms where `dlerror` is not thread-safe.
|
2020-08-20 14:34:40 -07:00
|
|
|
mod error {
|
|
|
|
use std::ffi::CStr;
|
|
|
|
use std::lazy::SyncLazy;
|
|
|
|
use std::sync::{Mutex, MutexGuard};
|
2015-01-10 22:53:22 +09:00
|
|
|
|
2020-08-20 14:34:40 -07:00
|
|
|
pub fn lock() -> MutexGuard<'static, Guard> {
|
|
|
|
static LOCK: SyncLazy<Mutex<Guard>> = SyncLazy::new(|| Mutex::new(Guard { _priv: () }));
|
|
|
|
LOCK.lock().unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Guard {
|
|
|
|
_priv: (),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Guard {
|
|
|
|
pub fn get(&mut self) -> Result<(), String> {
|
|
|
|
let msg = unsafe { libc::dlerror() };
|
|
|
|
if msg.is_null() {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
let msg = unsafe { CStr::from_ptr(msg as *const _) };
|
|
|
|
Err(msg.to_string_lossy().into_owned())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn clear(&mut self) {
|
|
|
|
let _ = unsafe { libc::dlerror() };
|
2020-03-22 00:20:58 +01:00
|
|
|
}
|
2013-06-08 23:29:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-20 14:34:40 -07:00
|
|
|
pub(super) fn open(filename: &OsStr) -> Result<*mut u8, String> {
|
|
|
|
let s = CString::new(filename.as_bytes()).unwrap();
|
|
|
|
|
|
|
|
let mut dlerror = error::lock();
|
2020-08-25 12:11:30 -07:00
|
|
|
let ret = unsafe { libc::dlopen(s.as_ptr(), libc::RTLD_LAZY | libc::RTLD_LOCAL) };
|
2020-08-20 14:34:40 -07:00
|
|
|
|
|
|
|
if !ret.is_null() {
|
2020-08-25 12:11:30 -07:00
|
|
|
return Ok(ret.cast());
|
2020-08-20 14:34:40 -07:00
|
|
|
}
|
|
|
|
|
2020-08-25 12:02:21 -07:00
|
|
|
// A NULL return from `dlopen` indicates that an error has definitely occurred, so if
|
|
|
|
// nothing is in `dlerror`, we are racing with another thread that has stolen our error
|
|
|
|
// message. See the explanation on the `dl::error` module for more information.
|
2020-08-20 14:34:40 -07:00
|
|
|
dlerror.get().and_then(|()| Err("Unknown error".to_string()))
|
|
|
|
}
|
|
|
|
|
2019-10-06 14:30:46 +03:00
|
|
|
pub(super) unsafe fn symbol(
|
|
|
|
handle: *mut u8,
|
|
|
|
symbol: *const libc::c_char,
|
|
|
|
) -> Result<*mut u8, String> {
|
2020-08-20 14:34:40 -07:00
|
|
|
let mut dlerror = error::lock();
|
|
|
|
|
2020-08-25 12:02:21 -07:00
|
|
|
// Unlike `dlopen`, it's possible for `dlsym` to return NULL without overwriting `dlerror`.
|
|
|
|
// Because of this, we clear `dlerror` before calling `dlsym` to avoid picking up a stale
|
|
|
|
// error message by accident.
|
|
|
|
dlerror.clear();
|
2020-08-20 14:34:40 -07:00
|
|
|
|
2020-08-25 12:11:30 -07:00
|
|
|
let ret = libc::dlsym(handle as *mut libc::c_void, symbol);
|
2020-08-20 14:34:40 -07:00
|
|
|
|
|
|
|
if !ret.is_null() {
|
2020-08-25 12:11:30 -07:00
|
|
|
return Ok(ret.cast());
|
2020-08-20 14:34:40 -07:00
|
|
|
}
|
|
|
|
|
2020-08-25 12:02:21 -07:00
|
|
|
// If `dlsym` returns NULL but there is nothing in `dlerror` it means one of two things:
|
|
|
|
// - We tried to load a symbol mapped to address 0. This is not technically an error but is
|
|
|
|
// unlikely to occur in practice and equally unlikely to be handled correctly by calling
|
|
|
|
// code. Therefore we treat it as an error anyway.
|
|
|
|
// - An error has occurred, but we are racing with another thread that has stolen our error
|
|
|
|
// message. See the explanation on the `dl::error` module for more information.
|
|
|
|
dlerror.get().and_then(|()| Err("Tried to load symbol mapped to address 0".to_string()))
|
2013-06-08 23:29:32 -07:00
|
|
|
}
|
2020-01-04 16:46:47 -05:00
|
|
|
|
2019-10-06 14:30:46 +03:00
|
|
|
pub(super) unsafe fn close(handle: *mut u8) {
|
2019-12-22 17:42:04 -05:00
|
|
|
libc::dlclose(handle as *mut libc::c_void);
|
2015-01-29 08:19:28 +01:00
|
|
|
}
|
2013-06-08 23:29:32 -07:00
|
|
|
}
|
|
|
|
|
2016-03-07 15:42:29 -08:00
|
|
|
#[cfg(windows)]
|
2015-01-10 22:53:22 +09:00
|
|
|
mod dl {
|
2016-03-07 15:42:29 -08:00
|
|
|
use std::ffi::OsStr;
|
|
|
|
use std::io;
|
|
|
|
use std::os::windows::prelude::*;
|
|
|
|
use std::ptr;
|
|
|
|
|
2020-01-04 16:46:47 -05:00
|
|
|
use winapi::shared::minwindef::HMODULE;
|
|
|
|
use winapi::um::errhandlingapi::SetThreadErrorMode;
|
2020-04-24 18:31:42 -04:00
|
|
|
use winapi::um::libloaderapi::{FreeLibrary, GetProcAddress, LoadLibraryW};
|
2020-01-04 16:46:47 -05:00
|
|
|
use winapi::um::winbase::SEM_FAILCRITICALERRORS;
|
2015-01-10 22:53:22 +09:00
|
|
|
|
2020-04-24 18:31:42 -04:00
|
|
|
pub(super) fn open(filename: &OsStr) -> Result<*mut u8, String> {
|
2015-01-10 22:53:22 +09:00
|
|
|
// disable "dll load failed" error dialog.
|
|
|
|
let prev_error_mode = unsafe {
|
2020-01-04 16:46:47 -05:00
|
|
|
let new_error_mode = SEM_FAILCRITICALERRORS;
|
2015-01-10 22:53:22 +09:00
|
|
|
let mut prev_error_mode = 0;
|
2019-12-22 17:42:04 -05:00
|
|
|
let result = SetThreadErrorMode(new_error_mode, &mut prev_error_mode);
|
2015-01-10 22:53:22 +09:00
|
|
|
if result == 0 {
|
2019-12-22 17:42:04 -05:00
|
|
|
return Err(io::Error::last_os_error().to_string());
|
2015-01-10 22:53:22 +09:00
|
|
|
}
|
|
|
|
prev_error_mode
|
|
|
|
};
|
2013-06-08 23:29:32 -07:00
|
|
|
|
2020-04-24 18:31:42 -04:00
|
|
|
let filename_str: Vec<_> = filename.encode_wide().chain(Some(0)).collect();
|
|
|
|
let result = unsafe { LoadLibraryW(filename_str.as_ptr()) } as *mut u8;
|
|
|
|
let result = ptr_result(result);
|
2015-01-10 22:53:22 +09:00
|
|
|
|
|
|
|
unsafe {
|
2016-03-07 15:42:29 -08:00
|
|
|
SetThreadErrorMode(prev_error_mode, ptr::null_mut());
|
2015-01-10 22:53:22 +09:00
|
|
|
}
|
2013-06-15 10:10:49 +02:00
|
|
|
|
2015-01-10 22:53:22 +09:00
|
|
|
result
|
2013-06-08 23:29:32 -07:00
|
|
|
}
|
|
|
|
|
2020-01-04 16:46:47 -05:00
|
|
|
pub(super) unsafe fn symbol(
|
|
|
|
handle: *mut u8,
|
|
|
|
symbol: *const libc::c_char,
|
|
|
|
) -> Result<*mut u8, String> {
|
2016-03-07 15:42:29 -08:00
|
|
|
let ptr = GetProcAddress(handle as HMODULE, symbol) as *mut u8;
|
|
|
|
ptr_result(ptr)
|
2013-06-08 23:29:32 -07:00
|
|
|
}
|
2013-10-03 21:34:35 -07:00
|
|
|
|
2019-10-06 14:30:46 +03:00
|
|
|
pub(super) unsafe fn close(handle: *mut u8) {
|
2016-03-07 15:42:29 -08:00
|
|
|
FreeLibrary(handle as HMODULE);
|
2015-10-24 20:51:34 -05:00
|
|
|
}
|
|
|
|
|
2016-03-07 15:42:29 -08:00
|
|
|
fn ptr_result<T>(ptr: *mut T) -> Result<*mut T, String> {
|
2019-12-22 17:42:04 -05:00
|
|
|
if ptr.is_null() { Err(io::Error::last_os_error().to_string()) } else { Ok(ptr) }
|
2015-10-24 20:51:34 -05:00
|
|
|
}
|
|
|
|
}
|