Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
27
third-party/vendor/libloading/src/os/mod.rs
vendored
Normal file
27
third-party/vendor/libloading/src/os/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//! Unsafe but flexible platform-specific bindings to dynamic library loading facilities.
|
||||
//!
|
||||
//! These modules expose more extensive and powerful bindings to the dynamic
|
||||
//! library loading facilities. Use of these bindings come at the cost of less (in most cases,
|
||||
//! none at all) safety guarantees, which are provided by the top-level bindings.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Using these modules will likely involve conditional compilation:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! # extern crate libloading;
|
||||
//! #[cfg(unix)]
|
||||
//! use libloading::os::unix::*;
|
||||
//! #[cfg(windows)]
|
||||
//! use libloading::os::windows::*;
|
||||
//! ```
|
||||
|
||||
/// UNIX implementation of dynamic library loading.
|
||||
#[cfg(any(unix, libloading_docs))]
|
||||
#[cfg_attr(libloading_docs, doc(cfg(unix)))]
|
||||
pub mod unix;
|
||||
|
||||
/// Windows implementation of dynamic library loading.
|
||||
#[cfg(any(windows, libloading_docs))]
|
||||
#[cfg_attr(libloading_docs, doc(cfg(windows)))]
|
||||
pub mod windows;
|
||||
247
third-party/vendor/libloading/src/os/unix/consts.rs
vendored
Normal file
247
third-party/vendor/libloading/src/os/unix/consts.rs
vendored
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
use std::os::raw::c_int;
|
||||
|
||||
/// Perform lazy binding.
|
||||
///
|
||||
/// Relocations shall be performed at an implementation-defined time, ranging from the time
|
||||
/// of the [`Library::open`] call until the first reference to a given symbol occurs.
|
||||
/// Specifying `RTLD_LAZY` should improve performance on implementations supporting dynamic
|
||||
/// symbol binding since a process might not reference all of the symbols in an executable
|
||||
/// object file. And, for systems supporting dynamic symbol resolution for normal process
|
||||
/// execution, this behaviour mimics the normal handling of process execution.
|
||||
///
|
||||
/// Conflicts with [`RTLD_NOW`].
|
||||
///
|
||||
/// [`Library::open`]: crate::os::unix::Library::open
|
||||
pub const RTLD_LAZY: c_int = posix::RTLD_LAZY;
|
||||
|
||||
/// Perform eager binding.
|
||||
///
|
||||
/// All necessary relocations shall be performed when the executable object file is first
|
||||
/// loaded. This may waste some processing if relocations are performed for symbols
|
||||
/// that are never referenced. This behaviour may be useful for applications that need to
|
||||
/// know that all symbols referenced during execution will be available before
|
||||
/// [`Library::open`] returns.
|
||||
///
|
||||
/// Conflicts with [`RTLD_LAZY`].
|
||||
///
|
||||
/// [`Library::open`]: crate::os::unix::Library::open
|
||||
pub const RTLD_NOW: c_int = posix::RTLD_NOW;
|
||||
|
||||
/// Make loaded symbols available for resolution globally.
|
||||
///
|
||||
/// The executable object file's symbols shall be made available for relocation processing of any
|
||||
/// other executable object file. In addition, calls to [`Library::get`] on `Library` obtained from
|
||||
/// [`Library::this`] allows executable object files loaded with this mode to be searched.
|
||||
///
|
||||
/// [`Library::this`]: crate::os::unix::Library::this
|
||||
/// [`Library::get`]: crate::os::unix::Library::get
|
||||
pub const RTLD_GLOBAL: c_int = posix::RTLD_GLOBAL;
|
||||
|
||||
/// Load symbols into an isolated namespace.
|
||||
///
|
||||
/// The executable object file's symbols shall not be made available for relocation processing of
|
||||
/// any other executable object file. This mode of operation is most appropriate for e.g. plugins.
|
||||
pub const RTLD_LOCAL: c_int = posix::RTLD_LOCAL;
|
||||
|
||||
#[cfg(all(libloading_docs, not(unix)))]
|
||||
mod posix {
|
||||
use super::c_int;
|
||||
pub(super) const RTLD_LAZY: c_int = !0;
|
||||
pub(super) const RTLD_NOW: c_int = !0;
|
||||
pub(super) const RTLD_GLOBAL: c_int = !0;
|
||||
pub(super) const RTLD_LOCAL: c_int = !0;
|
||||
}
|
||||
|
||||
#[cfg(any(not(libloading_docs), unix))]
|
||||
mod posix {
|
||||
extern crate cfg_if;
|
||||
use self::cfg_if::cfg_if;
|
||||
use super::c_int;
|
||||
cfg_if! {
|
||||
if #[cfg(target_os = "haiku")] {
|
||||
pub(super) const RTLD_LAZY: c_int = 0;
|
||||
} else if #[cfg(target_os = "aix")] {
|
||||
pub(super) const RTLD_LAZY: c_int = 4;
|
||||
} else if #[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
|
||||
target_env = "uclibc",
|
||||
target_env = "newlib",
|
||||
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
target_os = "hurd",
|
||||
))] {
|
||||
pub(super) const RTLD_LAZY: c_int = 1;
|
||||
} else {
|
||||
compile_error!(
|
||||
"Target has no known `RTLD_LAZY` value. Please submit an issue or PR adding it."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_os = "haiku")] {
|
||||
pub(super) const RTLD_NOW: c_int = 1;
|
||||
} else if #[cfg(any(
|
||||
target_os = "linux",
|
||||
all(target_os = "android", target_pointer_width = "64"),
|
||||
target_os = "emscripten",
|
||||
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
|
||||
target_os = "aix",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
|
||||
target_env = "uclibc",
|
||||
target_env = "newlib",
|
||||
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
target_os = "hurd",
|
||||
))] {
|
||||
pub(super) const RTLD_NOW: c_int = 2;
|
||||
} else if #[cfg(all(target_os = "android",target_pointer_width = "32"))] {
|
||||
pub(super) const RTLD_NOW: c_int = 0;
|
||||
} else {
|
||||
compile_error!(
|
||||
"Target has no known `RTLD_NOW` value. Please submit an issue or PR adding it."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(
|
||||
target_os = "haiku",
|
||||
all(target_os = "android",target_pointer_width = "32"),
|
||||
))] {
|
||||
pub(super) const RTLD_GLOBAL: c_int = 2;
|
||||
} else if #[cfg(target_os = "aix")] {
|
||||
pub(super) const RTLD_GLOBAL: c_int = 0x10000;
|
||||
} else if #[cfg(any(
|
||||
target_env = "uclibc",
|
||||
all(target_os = "linux", target_arch = "mips"),
|
||||
all(target_os = "linux", target_arch = "mips64"),
|
||||
))] {
|
||||
pub(super) const RTLD_GLOBAL: c_int = 4;
|
||||
} else if #[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
))] {
|
||||
pub(super) const RTLD_GLOBAL: c_int = 8;
|
||||
} else if #[cfg(any(
|
||||
target_os = "linux",
|
||||
all(target_os = "android", target_pointer_width = "64"),
|
||||
target_os = "emscripten",
|
||||
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
|
||||
target_env = "newlib",
|
||||
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
target_os = "hurd",
|
||||
))] {
|
||||
pub(super) const RTLD_GLOBAL: c_int = 0x100;
|
||||
} else {
|
||||
compile_error!(
|
||||
"Target has no known `RTLD_GLOBAL` value. Please submit an issue or PR adding it."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(
|
||||
target_os = "netbsd",
|
||||
target_os = "nto",
|
||||
))] {
|
||||
pub(super) const RTLD_LOCAL: c_int = 0x200;
|
||||
} else if #[cfg(target_os = "aix")] {
|
||||
pub(super) const RTLD_LOCAL: c_int = 0x80000;
|
||||
} else if #[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
))] {
|
||||
pub(super) const RTLD_LOCAL: c_int = 4;
|
||||
} else if #[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
|
||||
target_os = "haiku",
|
||||
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
|
||||
target_env = "uclibc",
|
||||
target_env = "newlib",
|
||||
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "hurd",
|
||||
))] {
|
||||
pub(super) const RTLD_LOCAL: c_int = 0;
|
||||
} else {
|
||||
compile_error!(
|
||||
"Target has no known `RTLD_LOCAL` value. Please submit an issue or PR adding it."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Other constants that exist but are not bound because they are platform-specific (non-posix)
|
||||
// extensions. Some of these constants are only relevant to `dlsym` or `dlmopen` calls.
|
||||
//
|
||||
// RTLD_CONFGEN
|
||||
// RTLD_DEFAULT
|
||||
// RTLD_DI_CONFIGADDR
|
||||
// RTLD_DI_LINKMAP
|
||||
// RTLD_DI_LMID
|
||||
// RTLD_DI_ORIGIN
|
||||
// RTLD_DI_PROFILENAME
|
||||
// RTLD_DI_PROFILEOUT
|
||||
// RTLD_DI_SERINFO
|
||||
// RTLD_DI_SERINFOSIZE
|
||||
// RTLD_DI_TLS_DATA
|
||||
// RTLD_DI_TLS_MODID
|
||||
// RTLD_FIRST
|
||||
// RTLD_GROUP
|
||||
// RTLD_NEXT
|
||||
// RTLD_PARENT
|
||||
// RTLD_PROBE
|
||||
// RTLD_SELF
|
||||
// RTLD_WORLD
|
||||
// RTLD_NODELETE
|
||||
// RTLD_NOLOAD
|
||||
// RTLD_DEEPBIND
|
||||
478
third-party/vendor/libloading/src/os/unix/mod.rs
vendored
Normal file
478
third-party/vendor/libloading/src/os/unix/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,478 @@
|
|||
// A hack for docs.rs to build documentation that has both windows and linux documentation in the
|
||||
// same rustdoc build visible.
|
||||
#[cfg(all(libloading_docs, not(unix)))]
|
||||
mod unix_imports {}
|
||||
#[cfg(any(not(libloading_docs), unix))]
|
||||
mod unix_imports {
|
||||
pub(super) use std::os::unix::ffi::OsStrExt;
|
||||
}
|
||||
|
||||
pub use self::consts::*;
|
||||
use self::unix_imports::*;
|
||||
use std::ffi::{CStr, OsStr};
|
||||
use std::os::raw;
|
||||
use std::{fmt, marker, mem, ptr};
|
||||
use util::{cstr_cow_from_bytes, ensure_compatible_types};
|
||||
|
||||
mod consts;
|
||||
|
||||
/// Run code and handle errors reported by `dlerror`.
|
||||
///
|
||||
/// This function first executes the `closure` function containing calls to the functions that
|
||||
/// report their errors via `dlerror`. This closure may return either `None` or `Some(*)` to
|
||||
/// further affect operation of this function.
|
||||
///
|
||||
/// In case the `closure` returns `None`, `with_dlerror` inspects the `dlerror`. `dlerror` may
|
||||
/// decide to not provide any error description, in which case `Err(None)` is returned to the
|
||||
/// caller. Otherwise the `error` callback is invoked to allow inspection and conversion of the
|
||||
/// error message. The conversion result is returned as `Err(Some(Error))`.
|
||||
///
|
||||
/// If the operations that report their errors via `dlerror` were all successful, `closure` should
|
||||
/// return `Some(T)` instead. In this case `dlerror` is not inspected at all.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// The whole `dlerror` handling scheme is done via setting and querying some global state. For
|
||||
/// that reason it is not safe to use dynamic library loading in MT-capable environment at all.
|
||||
/// Only in POSIX 2008+TC1 a thread-local state was allowed for `dlerror`, making the dl* family of
|
||||
/// functions possibly MT-safe, depending on the implementation of `dlerror`.
|
||||
///
|
||||
/// In practice (as of 2020-04-01) most of the widely used targets use a thread-local for error
|
||||
/// state and have been doing so for a long time.
|
||||
pub fn with_dlerror<T, F, Error>(closure: F, error: fn(&CStr) -> Error) -> Result<T, Option<Error>>
|
||||
where
|
||||
F: FnOnce() -> Option<T>,
|
||||
{
|
||||
// We used to guard all uses of dl* functions with our own mutex. This made them safe to use in
|
||||
// MT programs provided the only way a program used dl* was via this library. However, it also
|
||||
// had a number of downsides or cases where it failed to handle the problems. For instance,
|
||||
// if any other library called `dlerror` internally concurrently with `libloading` things would
|
||||
// still go awry.
|
||||
//
|
||||
// On platforms where `dlerror` is still MT-unsafe, `dlsym` (`Library::get`) can spuriously
|
||||
// succeed and return a null pointer for a symbol when the actual symbol look-up operation
|
||||
// fails. Instances where the actual symbol _could_ be `NULL` are platform specific. For
|
||||
// instance on GNU glibc based-systems (an excerpt from dlsym(3)):
|
||||
//
|
||||
// > The value of a symbol returned by dlsym() will never be NULL if the shared object is the
|
||||
// > result of normal compilation, since a global symbol is never placed at the NULL
|
||||
// > address. There are nevertheless cases where a lookup using dlsym() may return NULL as the
|
||||
// > value of a symbol. For example, the symbol value may be the result of a GNU indirect
|
||||
// > function (IFUNC) resolver function that returns NULL as the resolved value.
|
||||
|
||||
// While we could could call `dlerror` here to clear the previous error value, only the `dlsym`
|
||||
// call depends on it being cleared beforehand and only in some cases too. We will instead
|
||||
// clear the error inside the dlsym binding instead.
|
||||
//
|
||||
// In all the other cases, clearing the error here will only be hiding misuse of these bindings
|
||||
// or a bug in implementation of dl* family of functions.
|
||||
closure().ok_or_else(|| unsafe {
|
||||
// This code will only get executed if the `closure` returns `None`.
|
||||
let dlerror_str = dlerror();
|
||||
if dlerror_str.is_null() {
|
||||
// In non-dlsym case this may happen when there’re bugs in our bindings or there’s
|
||||
// non-libloading user of libdl; possibly in another thread.
|
||||
None
|
||||
} else {
|
||||
// You can’t even rely on error string being static here; call to subsequent dlerror
|
||||
// may invalidate or overwrite the error message. Why couldn’t they simply give up the
|
||||
// ownership over the message?
|
||||
// TODO: should do locale-aware conversion here. OTOH Rust doesn’t seem to work well in
|
||||
// any system that uses non-utf8 locale, so I doubt there’s a problem here.
|
||||
Some(error(CStr::from_ptr(dlerror_str)))
|
||||
// Since we do a copy of the error string above, maybe we should call dlerror again to
|
||||
// let libdl know it may free its copy of the string now?
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// A platform-specific counterpart of the cross-platform [`Library`](crate::Library).
|
||||
pub struct Library {
|
||||
handle: *mut raw::c_void,
|
||||
}
|
||||
|
||||
unsafe impl Send for Library {}
|
||||
|
||||
// That being said... this section in the volume 2 of POSIX.1-2008 states:
|
||||
//
|
||||
// > All functions defined by this volume of POSIX.1-2008 shall be thread-safe, except that the
|
||||
// > following functions need not be thread-safe.
|
||||
//
|
||||
// With notable absence of any dl* function other than dlerror in the list. By “this volume”
|
||||
// I suppose they refer precisely to the “volume 2”. dl* family of functions are specified
|
||||
// by this same volume, so the conclusion is indeed that dl* functions are required by POSIX
|
||||
// to be thread-safe. Great!
|
||||
//
|
||||
// See for more details:
|
||||
//
|
||||
// * https://github.com/nagisa/rust_libloading/pull/17
|
||||
// * http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_01
|
||||
unsafe impl Sync for Library {}
|
||||
|
||||
impl Library {
|
||||
/// Find and eagerly load a shared library (module).
|
||||
///
|
||||
/// If the `filename` contains a [path separator], the `filename` is interpreted as a `path` to
|
||||
/// a file. Otherwise, platform-specific algorithms are employed to find a library with a
|
||||
/// matching file name.
|
||||
///
|
||||
/// This is equivalent to <code>[Library::open](filename, [RTLD_LAZY] | [RTLD_LOCAL])</code>.
|
||||
///
|
||||
/// [path separator]: std::path::MAIN_SEPARATOR
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When a library is loaded, initialisation routines contained within the library are executed.
|
||||
/// For the purposes of safety, the execution of these routines is conceptually the same calling an
|
||||
/// unknown foreign function and may impose arbitrary requirements on the caller for the call
|
||||
/// to be sound.
|
||||
///
|
||||
/// Additionally, the callers of this function must also ensure that execution of the
|
||||
/// termination routines contained within the library is safe as well. These routines may be
|
||||
/// executed when the library is unloaded.
|
||||
#[inline]
|
||||
pub unsafe fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error> {
|
||||
Library::open(Some(filename), RTLD_LAZY | RTLD_LOCAL)
|
||||
}
|
||||
|
||||
/// Load the `Library` representing the current executable.
|
||||
///
|
||||
/// [`Library::get`] calls of the returned `Library` will look for symbols in following
|
||||
/// locations in order:
|
||||
///
|
||||
/// 1. The original program image;
|
||||
/// 2. Any executable object files (e.g. shared libraries) loaded at program startup;
|
||||
/// 3. Any executable object files loaded at runtime (e.g. via other `Library::new` calls or via
|
||||
/// calls to the `dlopen` function).
|
||||
///
|
||||
/// Note that the behaviour of a `Library` loaded with this method is different from that of
|
||||
/// Libraries loaded with [`os::windows::Library::this`].
|
||||
///
|
||||
/// This is equivalent to <code>[Library::open](None, [RTLD_LAZY] | [RTLD_LOCAL])</code>.
|
||||
///
|
||||
/// [`os::windows::Library::this`]: crate::os::windows::Library::this
|
||||
#[inline]
|
||||
pub fn this() -> Library {
|
||||
unsafe {
|
||||
// SAFE: this does not load any new shared library images, no danger in it executing
|
||||
// initialiser routines.
|
||||
Library::open(None::<&OsStr>, RTLD_LAZY | RTLD_LOCAL).expect("this should never fail")
|
||||
}
|
||||
}
|
||||
|
||||
/// Find and load an executable object file (shared library).
|
||||
///
|
||||
/// See documentation for [`Library::this`] for further description of the behaviour
|
||||
/// when the `filename` is `None`. Otherwise see [`Library::new`].
|
||||
///
|
||||
/// Corresponds to `dlopen(filename, flags)`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When a library is loaded, initialisation routines contained within the library are executed.
|
||||
/// For the purposes of safety, the execution of these routines is conceptually the same calling an
|
||||
/// unknown foreign function and may impose arbitrary requirements on the caller for the call
|
||||
/// to be sound.
|
||||
///
|
||||
/// Additionally, the callers of this function must also ensure that execution of the
|
||||
/// termination routines contained within the library is safe as well. These routines may be
|
||||
/// executed when the library is unloaded.
|
||||
pub unsafe fn open<P>(filename: Option<P>, flags: raw::c_int) -> Result<Library, crate::Error>
|
||||
where
|
||||
P: AsRef<OsStr>,
|
||||
{
|
||||
let filename = match filename {
|
||||
None => None,
|
||||
Some(ref f) => Some(cstr_cow_from_bytes(f.as_ref().as_bytes())?),
|
||||
};
|
||||
with_dlerror(
|
||||
move || {
|
||||
let result = dlopen(
|
||||
match filename {
|
||||
None => ptr::null(),
|
||||
Some(ref f) => f.as_ptr(),
|
||||
},
|
||||
flags,
|
||||
);
|
||||
// ensure filename lives until dlopen completes
|
||||
drop(filename);
|
||||
if result.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Library { handle: result })
|
||||
}
|
||||
},
|
||||
|desc| crate::Error::DlOpen { desc: desc.into() },
|
||||
)
|
||||
.map_err(|e| e.unwrap_or(crate::Error::DlOpenUnknown))
|
||||
}
|
||||
|
||||
unsafe fn get_impl<T, F>(&self, symbol: &[u8], on_null: F) -> Result<Symbol<T>, crate::Error>
|
||||
where
|
||||
F: FnOnce() -> Result<Symbol<T>, crate::Error>,
|
||||
{
|
||||
ensure_compatible_types::<T, *mut raw::c_void>()?;
|
||||
let symbol = cstr_cow_from_bytes(symbol)?;
|
||||
// `dlsym` may return nullptr in two cases: when a symbol genuinely points to a null
|
||||
// pointer or the symbol cannot be found. In order to detect this case a double dlerror
|
||||
// pattern must be used, which is, sadly, a little bit racy.
|
||||
//
|
||||
// We try to leave as little space as possible for this to occur, but we can’t exactly
|
||||
// fully prevent it.
|
||||
let result = with_dlerror(
|
||||
|| {
|
||||
dlerror();
|
||||
let symbol = dlsym(self.handle, symbol.as_ptr());
|
||||
if symbol.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Symbol {
|
||||
pointer: symbol,
|
||||
pd: marker::PhantomData,
|
||||
})
|
||||
}
|
||||
},
|
||||
|desc| crate::Error::DlSym { desc: desc.into() },
|
||||
);
|
||||
match result {
|
||||
Err(None) => on_null(),
|
||||
Err(Some(e)) => Err(e),
|
||||
Ok(x) => Ok(x),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a pointer to a function or static variable by symbol name.
|
||||
///
|
||||
/// The `symbol` may not contain any null bytes, with the exception of the last byte. Providing a
|
||||
/// null terminated `symbol` may help to avoid an allocation.
|
||||
///
|
||||
/// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
|
||||
/// most likely invalid.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Users of this API must specify the correct type of the function or variable loaded. Using a
|
||||
/// `Symbol` with a wrong type is undefined.
|
||||
///
|
||||
/// # Platform-specific behaviour
|
||||
///
|
||||
/// Implementation of thread local variables is extremely platform specific and uses of such
|
||||
/// variables that work on e.g. Linux may have unintended behaviour on other targets.
|
||||
///
|
||||
/// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such
|
||||
/// as FreeBSD), this function will unconditionally return an error when the underlying `dlsym`
|
||||
/// call returns a null pointer. There are rare situations where `dlsym` returns a genuine null
|
||||
/// pointer without it being an error. If loading a null pointer is something you care about,
|
||||
/// consider using the [`Library::get_singlethreaded`] call.
|
||||
#[inline(always)]
|
||||
pub unsafe fn get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
|
||||
extern crate cfg_if;
|
||||
cfg_if::cfg_if! {
|
||||
// These targets are known to have MT-safe `dlerror`.
|
||||
if #[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "openbsd",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "redox",
|
||||
target_os = "fuchsia"
|
||||
))] {
|
||||
self.get_singlethreaded(symbol)
|
||||
} else {
|
||||
self.get_impl(symbol, || Err(crate::Error::DlSymUnknown))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a pointer to function or static variable by symbol name.
|
||||
///
|
||||
/// The `symbol` may not contain any null bytes, with the exception of the last byte. Providing a
|
||||
/// null terminated `symbol` may help to avoid an allocation.
|
||||
///
|
||||
/// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
|
||||
/// most likely invalid.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Users of this API must specify the correct type of the function or variable loaded.
|
||||
///
|
||||
/// It is up to the user of this library to ensure that no other calls to an MT-unsafe
|
||||
/// implementation of `dlerror` occur during the execution of this function. Failing that, the
|
||||
/// behaviour of this function is not defined.
|
||||
///
|
||||
/// # Platform-specific behaviour
|
||||
///
|
||||
/// The implementation of thread-local variables is extremely platform specific and uses of such
|
||||
/// variables that work on e.g. Linux may have unintended behaviour on other targets.
|
||||
#[inline(always)]
|
||||
pub unsafe fn get_singlethreaded<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
|
||||
self.get_impl(symbol, || {
|
||||
Ok(Symbol {
|
||||
pointer: ptr::null_mut(),
|
||||
pd: marker::PhantomData,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Convert the `Library` to a raw handle.
|
||||
///
|
||||
/// The handle returned by this function shall be usable with APIs which accept handles
|
||||
/// as returned by `dlopen`.
|
||||
pub fn into_raw(self) -> *mut raw::c_void {
|
||||
let handle = self.handle;
|
||||
mem::forget(self);
|
||||
handle
|
||||
}
|
||||
|
||||
/// Convert a raw handle returned by `dlopen`-family of calls to a `Library`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The pointer shall be a result of a successful call of the `dlopen`-family of functions or a
|
||||
/// pointer previously returned by `Library::into_raw` call. It must be valid to call `dlclose`
|
||||
/// with this pointer as an argument.
|
||||
pub unsafe fn from_raw(handle: *mut raw::c_void) -> Library {
|
||||
Library { handle }
|
||||
}
|
||||
|
||||
/// Unload the library.
|
||||
///
|
||||
/// This method might be a no-op, depending on the flags with which the `Library` was opened,
|
||||
/// what library was opened or other platform specifics.
|
||||
///
|
||||
/// You only need to call this if you are interested in handling any errors that may arise when
|
||||
/// library is unloaded. Otherwise the implementation of `Drop` for `Library` will close the
|
||||
/// library and ignore the errors were they arise.
|
||||
///
|
||||
/// The underlying data structures may still get leaked if an error does occur.
|
||||
pub fn close(self) -> Result<(), crate::Error> {
|
||||
let result = with_dlerror(
|
||||
|| {
|
||||
if unsafe { dlclose(self.handle) } == 0 {
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
|desc| crate::Error::DlClose { desc: desc.into() },
|
||||
)
|
||||
.map_err(|e| e.unwrap_or(crate::Error::DlCloseUnknown));
|
||||
// While the library is not free'd yet in case of an error, there is no reason to try
|
||||
// dropping it again, because all that will do is try calling `dlclose` again. only
|
||||
// this time it would ignore the return result, which we already seen failing…
|
||||
std::mem::forget(self);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Library {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
dlclose(self.handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Library {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(&format!("Library@{:p}", self.handle))
|
||||
}
|
||||
}
|
||||
|
||||
/// Symbol from a library.
|
||||
///
|
||||
/// A major difference compared to the cross-platform `Symbol` is that this does not ensure that the
|
||||
/// `Symbol` does not outlive the `Library` it comes from.
|
||||
pub struct Symbol<T> {
|
||||
pointer: *mut raw::c_void,
|
||||
pd: marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Symbol<T> {
|
||||
/// Convert the loaded `Symbol` into a raw pointer.
|
||||
pub fn into_raw(self) -> *mut raw::c_void {
|
||||
self.pointer
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Symbol<Option<T>> {
|
||||
/// Lift Option out of the symbol.
|
||||
pub fn lift_option(self) -> Option<Symbol<T>> {
|
||||
if self.pointer.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Symbol {
|
||||
pointer: self.pointer,
|
||||
pd: marker::PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for Symbol<T> {}
|
||||
unsafe impl<T: Sync> Sync for Symbol<T> {}
|
||||
|
||||
impl<T> Clone for Symbol<T> {
|
||||
fn clone(&self) -> Symbol<T> {
|
||||
Symbol { ..*self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ::std::ops::Deref for Symbol<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
unsafe {
|
||||
// Additional reference level for a dereference on `deref` return value.
|
||||
&*(&self.pointer as *const *mut _ as *const T)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Symbol<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
unsafe {
|
||||
let mut info = mem::MaybeUninit::<DlInfo>::uninit();
|
||||
if dladdr(self.pointer, info.as_mut_ptr()) != 0 {
|
||||
let info = info.assume_init();
|
||||
if info.dli_sname.is_null() {
|
||||
f.write_str(&format!(
|
||||
"Symbol@{:p} from {:?}",
|
||||
self.pointer,
|
||||
CStr::from_ptr(info.dli_fname)
|
||||
))
|
||||
} else {
|
||||
f.write_str(&format!(
|
||||
"Symbol {:?}@{:p} from {:?}",
|
||||
CStr::from_ptr(info.dli_sname),
|
||||
self.pointer,
|
||||
CStr::from_ptr(info.dli_fname)
|
||||
))
|
||||
}
|
||||
} else {
|
||||
f.write_str(&format!("Symbol@{:p}", self.pointer))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Platform specific things
|
||||
#[cfg_attr(any(target_os = "linux", target_os = "android"), link(name = "dl"))]
|
||||
#[cfg_attr(any(target_os = "freebsd", target_os = "dragonfly"), link(name = "c"))]
|
||||
extern "C" {
|
||||
fn dlopen(filename: *const raw::c_char, flags: raw::c_int) -> *mut raw::c_void;
|
||||
fn dlclose(handle: *mut raw::c_void) -> raw::c_int;
|
||||
fn dlsym(handle: *mut raw::c_void, symbol: *const raw::c_char) -> *mut raw::c_void;
|
||||
fn dlerror() -> *mut raw::c_char;
|
||||
fn dladdr(addr: *mut raw::c_void, info: *mut DlInfo) -> raw::c_int;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct DlInfo {
|
||||
dli_fname: *const raw::c_char,
|
||||
dli_fbase: *mut raw::c_void,
|
||||
dli_sname: *const raw::c_char,
|
||||
dli_saddr: *mut raw::c_void,
|
||||
}
|
||||
512
third-party/vendor/libloading/src/os/windows/mod.rs
vendored
Normal file
512
third-party/vendor/libloading/src/os/windows/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,512 @@
|
|||
// A hack for docs.rs to build documentation that has both windows and linux documentation in the
|
||||
// same rustdoc build visible.
|
||||
#[cfg(all(libloading_docs, not(windows)))]
|
||||
mod windows_imports {}
|
||||
#[cfg(any(not(libloading_docs), windows))]
|
||||
mod windows_imports {
|
||||
use super::{DWORD, BOOL, HANDLE, HMODULE, FARPROC};
|
||||
pub(super) use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> DWORD);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetThreadErrorMode(new_mode: DWORD, old_mode: *mut DWORD) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleExW(flags: u32, module_name: *const u16, module: *mut HMODULE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FreeLibrary(module: HMODULE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn LoadLibraryExW(filename: *const u16, file: HANDLE, flags: DWORD) -> HMODULE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetModuleFileNameW(module: HMODULE, filename: *mut u16, size: DWORD) -> DWORD);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(module: HMODULE, procname: *const u8) -> FARPROC);
|
||||
}
|
||||
|
||||
use self::windows_imports::*;
|
||||
use util::{ensure_compatible_types, cstr_cow_from_bytes};
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::{fmt, io, marker, mem, ptr};
|
||||
|
||||
/// The platform-specific counterpart of the cross-platform [`Library`](crate::Library).
|
||||
pub struct Library(HMODULE);
|
||||
|
||||
unsafe impl Send for Library {}
|
||||
// Now, this is sort-of-tricky. MSDN documentation does not really make any claims as to safety of
|
||||
// the Win32 APIs. Sadly, whomever I asked, even current and former Microsoft employees, couldn’t
|
||||
// say for sure whether the Win32 APIs used to implement `Library` are thread-safe or not.
|
||||
//
|
||||
// My investigation ended up with a question about thread-safety properties of the API involved
|
||||
// being sent to an internal (to MS) general question mailing-list. The conclusion of the mail is
|
||||
// as such:
|
||||
//
|
||||
// * Nobody inside MS (at least out of all of the people who have seen the question) knows for
|
||||
// sure either;
|
||||
// * However, the general consensus between MS developers is that one can rely on the API being
|
||||
// thread-safe. In case it is not thread-safe it should be considered a bug on the Windows
|
||||
// part. (NB: bugs filed at https://connect.microsoft.com/ against Windows Server)
|
||||
unsafe impl Sync for Library {}
|
||||
|
||||
impl Library {
|
||||
/// Find and load a module.
|
||||
///
|
||||
/// If the `filename` specifies a full path, the function only searches that path for the
|
||||
/// module. Otherwise, if the `filename` specifies a relative path or a module name without a
|
||||
/// path, the function uses a Windows-specific search strategy to find the module. For more
|
||||
/// information, see the [Remarks on MSDN][msdn].
|
||||
///
|
||||
/// If the `filename` specifies a library filename without a path and with the extension omitted,
|
||||
/// the `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
|
||||
/// trailing `.` to the `filename`.
|
||||
///
|
||||
/// This is equivalent to <code>[Library::load_with_flags](filename, 0)</code>.
|
||||
///
|
||||
/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw#remarks
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When a library is loaded, initialisation routines contained within the library are executed.
|
||||
/// For the purposes of safety, the execution of these routines is conceptually the same calling an
|
||||
/// unknown foreign function and may impose arbitrary requirements on the caller for the call
|
||||
/// to be sound.
|
||||
///
|
||||
/// Additionally, the callers of this function must also ensure that execution of the
|
||||
/// termination routines contained within the library is safe as well. These routines may be
|
||||
/// executed when the library is unloaded.
|
||||
#[inline]
|
||||
pub unsafe fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error> {
|
||||
Library::load_with_flags(filename, 0)
|
||||
}
|
||||
|
||||
/// Get the `Library` representing the original program executable.
|
||||
///
|
||||
/// Note that the behaviour of the `Library` loaded with this method is different from
|
||||
/// Libraries loaded with [`os::unix::Library::this`]. For more information refer to [MSDN].
|
||||
///
|
||||
/// Corresponds to `GetModuleHandleExW(0, NULL, _)`.
|
||||
///
|
||||
/// [`os::unix::Library::this`]: crate::os::unix::Library::this
|
||||
/// [MSDN]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw
|
||||
pub fn this() -> Result<Library, crate::Error> {
|
||||
unsafe {
|
||||
let mut handle: HMODULE = 0;
|
||||
with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || {
|
||||
let result = GetModuleHandleExW(0, std::ptr::null_mut(), &mut handle);
|
||||
if result == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(Library(handle))
|
||||
}
|
||||
}).map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a module that is already loaded by the program.
|
||||
///
|
||||
/// This function returns a `Library` corresponding to a module with the given name that is
|
||||
/// already mapped into the address space of the process. If the module isn't found, an error is
|
||||
/// returned.
|
||||
///
|
||||
/// If the `filename` does not include a full path and there are multiple different loaded
|
||||
/// modules corresponding to the `filename`, it is impossible to predict which module handle
|
||||
/// will be returned. For more information refer to [MSDN].
|
||||
///
|
||||
/// If the `filename` specifies a library filename without a path and with the extension omitted,
|
||||
/// the `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
|
||||
/// trailing `.` to the `filename`.
|
||||
///
|
||||
/// This is equivalent to `GetModuleHandleExW(0, filename, _)`.
|
||||
///
|
||||
/// [MSDN]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw
|
||||
pub fn open_already_loaded<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error> {
|
||||
let wide_filename: Vec<u16> = filename.as_ref().encode_wide().chain(Some(0)).collect();
|
||||
|
||||
let ret = unsafe {
|
||||
let mut handle: HMODULE = 0;
|
||||
with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || {
|
||||
// Make sure no winapi calls as a result of drop happen inside this closure, because
|
||||
// otherwise that might change the return value of the GetLastError.
|
||||
let result = GetModuleHandleExW(0, wide_filename.as_ptr(), &mut handle);
|
||||
if result == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(Library(handle))
|
||||
}
|
||||
}).map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown))
|
||||
};
|
||||
|
||||
drop(wide_filename); // Drop wide_filename here to ensure it doesn’t get moved and dropped
|
||||
// inside the closure by mistake. See comment inside the closure.
|
||||
ret
|
||||
}
|
||||
|
||||
/// Find and load a module, additionally adjusting behaviour with flags.
|
||||
///
|
||||
/// See [`Library::new`] for documentation on the handling of the `filename` argument. See the
|
||||
/// [flag table on MSDN][flags] for information on applicable values for the `flags` argument.
|
||||
///
|
||||
/// Corresponds to `LoadLibraryExW(filename, reserved: NULL, flags)`.
|
||||
///
|
||||
/// [flags]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When a library is loaded, initialisation routines contained within the library are executed.
|
||||
/// For the purposes of safety, the execution of these routines is conceptually the same calling an
|
||||
/// unknown foreign function and may impose arbitrary requirements on the caller for the call
|
||||
/// to be sound.
|
||||
///
|
||||
/// Additionally, the callers of this function must also ensure that execution of the
|
||||
/// termination routines contained within the library is safe as well. These routines may be
|
||||
/// executed when the library is unloaded.
|
||||
pub unsafe fn load_with_flags<P: AsRef<OsStr>>(filename: P, flags: LOAD_LIBRARY_FLAGS) -> Result<Library, crate::Error> {
|
||||
let wide_filename: Vec<u16> = filename.as_ref().encode_wide().chain(Some(0)).collect();
|
||||
let _guard = ErrorModeGuard::new();
|
||||
|
||||
let ret = with_get_last_error(|source| crate::Error::LoadLibraryExW { source }, || {
|
||||
// Make sure no winapi calls as a result of drop happen inside this closure, because
|
||||
// otherwise that might change the return value of the GetLastError.
|
||||
let handle = LoadLibraryExW(wide_filename.as_ptr(), 0, flags);
|
||||
if handle == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(Library(handle))
|
||||
}
|
||||
}).map_err(|e| e.unwrap_or(crate::Error::LoadLibraryExWUnknown));
|
||||
drop(wide_filename); // Drop wide_filename here to ensure it doesn’t get moved and dropped
|
||||
// inside the closure by mistake. See comment inside the closure.
|
||||
ret
|
||||
}
|
||||
|
||||
/// Get a pointer to a function or static variable by symbol name.
|
||||
///
|
||||
/// The `symbol` may not contain any null bytes, with the exception of the last byte. A null
|
||||
/// terminated `symbol` may avoid a string allocation in some cases.
|
||||
///
|
||||
/// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
|
||||
/// most likely invalid.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Users of this API must specify the correct type of the function or variable loaded.
|
||||
pub unsafe fn get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
|
||||
ensure_compatible_types::<T, FARPROC>()?;
|
||||
let symbol = cstr_cow_from_bytes(symbol)?;
|
||||
with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
|
||||
let symbol = GetProcAddress(self.0, symbol.as_ptr().cast());
|
||||
if symbol.is_none() {
|
||||
None
|
||||
} else {
|
||||
Some(Symbol {
|
||||
pointer: symbol,
|
||||
pd: marker::PhantomData
|
||||
})
|
||||
}
|
||||
}).map_err(|e| e.unwrap_or(crate::Error::GetProcAddressUnknown))
|
||||
}
|
||||
|
||||
/// Get a pointer to a function or static variable by ordinal number.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Users of this API must specify the correct type of the function or variable loaded.
|
||||
pub unsafe fn get_ordinal<T>(&self, ordinal: u16) -> Result<Symbol<T>, crate::Error> {
|
||||
ensure_compatible_types::<T, FARPROC>()?;
|
||||
with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
|
||||
let ordinal = ordinal as usize as *const _;
|
||||
let symbol = GetProcAddress(self.0, ordinal);
|
||||
if symbol.is_none() {
|
||||
None
|
||||
} else {
|
||||
Some(Symbol {
|
||||
pointer: symbol,
|
||||
pd: marker::PhantomData
|
||||
})
|
||||
}
|
||||
}).map_err(|e| e.unwrap_or(crate::Error::GetProcAddressUnknown))
|
||||
}
|
||||
|
||||
/// Convert the `Library` to a raw handle.
|
||||
pub fn into_raw(self) -> HMODULE {
|
||||
let handle = self.0;
|
||||
mem::forget(self);
|
||||
handle
|
||||
}
|
||||
|
||||
/// Convert a raw handle to a `Library`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The handle must be the result of a successful call of `LoadLibraryA`, `LoadLibraryW`,
|
||||
/// `LoadLibraryExW`, or `LoadLibraryExA`, or a handle previously returned by the
|
||||
/// `Library::into_raw` call.
|
||||
pub unsafe fn from_raw(handle: HMODULE) -> Library {
|
||||
Library(handle)
|
||||
}
|
||||
|
||||
/// Unload the library.
|
||||
///
|
||||
/// You only need to call this if you are interested in handling any errors that may arise when
|
||||
/// library is unloaded. Otherwise this will be done when `Library` is dropped.
|
||||
///
|
||||
/// The underlying data structures may still get leaked if an error does occur.
|
||||
pub fn close(self) -> Result<(), crate::Error> {
|
||||
let result = with_get_last_error(|source| crate::Error::FreeLibrary { source }, || {
|
||||
if unsafe { FreeLibrary(self.0) == 0 } {
|
||||
None
|
||||
} else {
|
||||
Some(())
|
||||
}
|
||||
}).map_err(|e| e.unwrap_or(crate::Error::FreeLibraryUnknown));
|
||||
// While the library is not free'd yet in case of an error, there is no reason to try
|
||||
// dropping it again, because all that will do is try calling `FreeLibrary` again. only
|
||||
// this time it would ignore the return result, which we already seen failing...
|
||||
std::mem::forget(self);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Library {
|
||||
fn drop(&mut self) {
|
||||
unsafe { FreeLibrary(self.0); }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Library {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
unsafe {
|
||||
// FIXME: use Maybeuninit::uninit_array when stable
|
||||
let mut buf =
|
||||
mem::MaybeUninit::<[mem::MaybeUninit<u16>; 1024]>::uninit().assume_init();
|
||||
let len = GetModuleFileNameW(self.0,
|
||||
buf[..].as_mut_ptr().cast(), 1024) as usize;
|
||||
if len == 0 {
|
||||
f.write_str(&format!("Library@{:#x}", self.0))
|
||||
} else {
|
||||
let string: OsString = OsString::from_wide(
|
||||
// FIXME: use Maybeuninit::slice_get_ref when stable
|
||||
&*(&buf[..len] as *const [_] as *const [u16]),
|
||||
);
|
||||
f.write_str(&format!("Library@{:#x} from {:?}", self.0, string))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A symbol from a library.
|
||||
///
|
||||
/// A major difference compared to the cross-platform `Symbol` is that this does not ensure that the
|
||||
/// `Symbol` does not outlive the `Library` that it comes from.
|
||||
pub struct Symbol<T> {
|
||||
pointer: FARPROC,
|
||||
pd: marker::PhantomData<T>
|
||||
}
|
||||
|
||||
impl<T> Symbol<T> {
|
||||
/// Convert the loaded `Symbol` into a handle.
|
||||
pub fn into_raw(self) -> FARPROC {
|
||||
self.pointer
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Symbol<Option<T>> {
|
||||
/// Lift Option out of the symbol.
|
||||
pub fn lift_option(self) -> Option<Symbol<T>> {
|
||||
if self.pointer.is_none() {
|
||||
None
|
||||
} else {
|
||||
Some(Symbol {
|
||||
pointer: self.pointer,
|
||||
pd: marker::PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for Symbol<T> {}
|
||||
unsafe impl<T: Sync> Sync for Symbol<T> {}
|
||||
|
||||
impl<T> Clone for Symbol<T> {
|
||||
fn clone(&self) -> Symbol<T> {
|
||||
Symbol { ..*self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ::std::ops::Deref for Symbol<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*((&self.pointer) as *const FARPROC as *const T) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Symbol<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.pointer {
|
||||
None => f.write_str("Symbol@0x0"),
|
||||
Some(ptr) => f.write_str(&format!("Symbol@{:p}", ptr as *const ())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ErrorModeGuard(DWORD);
|
||||
|
||||
impl ErrorModeGuard {
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
fn new() -> Option<ErrorModeGuard> {
|
||||
unsafe {
|
||||
let mut previous_mode = 0;
|
||||
if SetThreadErrorMode(SEM_FAILCRITICALERRORS, &mut previous_mode) == 0 {
|
||||
// How in the world is it possible for what is essentially a simple variable swap
|
||||
// to fail? For now we just ignore the error -- the worst that can happen here is
|
||||
// the previous mode staying on and user seeing a dialog error on older Windows
|
||||
// machines.
|
||||
None
|
||||
} else if previous_mode == SEM_FAILCRITICALERRORS {
|
||||
None
|
||||
} else {
|
||||
Some(ErrorModeGuard(previous_mode))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ErrorModeGuard {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
SetThreadErrorMode(self.0, ptr::null_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn with_get_last_error<T, F>(wrap: fn(crate::error::WindowsError) -> crate::Error, closure: F)
|
||||
-> Result<T, Option<crate::Error>>
|
||||
where F: FnOnce() -> Option<T> {
|
||||
closure().ok_or_else(|| {
|
||||
let error = unsafe { GetLastError() };
|
||||
if error == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(wrap(crate::error::WindowsError(io::Error::from_raw_os_error(error as i32))))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
type BOOL = i32;
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
type DWORD = u32;
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
type HANDLE = isize;
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
type HMODULE = isize;
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
type FARPROC = Option<unsafe extern "system" fn() -> isize>;
|
||||
#[allow(non_camel_case_types)]
|
||||
type LOAD_LIBRARY_FLAGS = DWORD;
|
||||
|
||||
const SEM_FAILCRITICALERRORS: DWORD = 1;
|
||||
|
||||
/// Do not check AppLocker rules or apply Software Restriction Policies for the DLL.
|
||||
///
|
||||
/// This action applies only to the DLL being loaded and not to its dependencies. This value is
|
||||
/// recommended for use in setup programs that must run extracted DLLs during installation.
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: LOAD_LIBRARY_FLAGS = 0x00000010;
|
||||
|
||||
/// Map the file into the calling process’ virtual address space as if it were a data file.
|
||||
///
|
||||
/// Nothing is done to execute or prepare to execute the mapped file. Therefore, you cannot call
|
||||
/// functions like [`Library::get`] with this DLL. Using this value causes writes to read-only
|
||||
/// memory to raise an access violation. Use this flag when you want to load a DLL only to extract
|
||||
/// messages or resources from it.
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
pub const LOAD_LIBRARY_AS_DATAFILE: LOAD_LIBRARY_FLAGS = 0x00000002;
|
||||
|
||||
/// Map the file into the calling process’ virtual address space as if it were a data file.
|
||||
///
|
||||
/// Similar to [`LOAD_LIBRARY_AS_DATAFILE`], except that the DLL file is opened with exclusive
|
||||
/// write access for the calling process. Other processes cannot open the DLL file for write access
|
||||
/// while it is in use. However, the DLL can still be opened by other processes.
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: LOAD_LIBRARY_FLAGS = 0x00000040;
|
||||
|
||||
/// Map the file into the process’ virtual address space as an image file.
|
||||
///
|
||||
/// The loader does not load the static imports or perform the other usual initialisation steps.
|
||||
/// Use this flag when you want to load a DLL only to extract messages or resources from it.
|
||||
///
|
||||
/// Unless the application depends on the file having the in-memory layout of an image, this value
|
||||
/// should be used with either [`LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE`] or
|
||||
/// [`LOAD_LIBRARY_AS_DATAFILE`].
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: LOAD_LIBRARY_FLAGS = 0x00000020;
|
||||
|
||||
/// Search the application's installation directory for the DLL and its dependencies.
|
||||
///
|
||||
/// Directories in the standard search path are not searched. This value cannot be combined with
|
||||
/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: LOAD_LIBRARY_FLAGS = 0x00000200;
|
||||
|
||||
/// Search default directories when looking for the DLL and its dependencies.
|
||||
///
|
||||
/// This value is a combination of [`LOAD_LIBRARY_SEARCH_APPLICATION_DIR`],
|
||||
/// [`LOAD_LIBRARY_SEARCH_SYSTEM32`], and [`LOAD_LIBRARY_SEARCH_USER_DIRS`]. Directories in the
|
||||
/// standard search path are not searched. This value cannot be combined with
|
||||
/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 0x00001000;
|
||||
|
||||
/// Directory that contains the DLL is temporarily added to the beginning of the list of
|
||||
/// directories that are searched for the DLL’s dependencies.
|
||||
///
|
||||
/// Directories in the standard search path are not searched.
|
||||
///
|
||||
/// The `filename` parameter must specify a fully qualified path. This value cannot be combined
|
||||
/// with [`LOAD_WITH_ALTERED_SEARCH_PATH`].
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: LOAD_LIBRARY_FLAGS = 0x00000100;
|
||||
|
||||
/// Search `%windows%\system32` for the DLL and its dependencies.
|
||||
///
|
||||
/// Directories in the standard search path are not searched. This value cannot be combined with
|
||||
/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
pub const LOAD_LIBRARY_SEARCH_SYSTEM32: LOAD_LIBRARY_FLAGS = 0x00000800;
|
||||
|
||||
/// Directories added using the `AddDllDirectory` or the `SetDllDirectory` function are searched
|
||||
/// for the DLL and its dependencies.
|
||||
///
|
||||
/// If more than one directory has been added, the order in which the directories are searched is
|
||||
/// unspecified. Directories in the standard search path are not searched. This value cannot be
|
||||
/// combined with [`LOAD_WITH_ALTERED_SEARCH_PATH`].
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
pub const LOAD_LIBRARY_SEARCH_USER_DIRS: LOAD_LIBRARY_FLAGS = 0x00000400;
|
||||
|
||||
/// If `filename` specifies an absolute path, the system uses the alternate file search strategy
|
||||
/// discussed in the [Remarks section] to find associated executable modules that the specified
|
||||
/// module causes to be loaded.
|
||||
///
|
||||
/// If this value is used and `filename` specifies a relative path, the behaviour is undefined.
|
||||
///
|
||||
/// If this value is not used, or if `filename` does not specify a path, the system uses the
|
||||
/// standard search strategy discussed in the [Remarks section] to find associated executable
|
||||
/// modules that the specified module causes to be loaded.
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
///
|
||||
/// [Remarks]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#remarks
|
||||
pub const LOAD_WITH_ALTERED_SEARCH_PATH: LOAD_LIBRARY_FLAGS = 0x00000008;
|
||||
|
||||
/// Specifies that the digital signature of the binary image must be checked at load time.
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: LOAD_LIBRARY_FLAGS = 0x00000080;
|
||||
|
||||
/// Allow loading a DLL for execution from the current directory only if it is under a directory in
|
||||
/// the Safe load list.
|
||||
///
|
||||
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
|
||||
pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: LOAD_LIBRARY_FLAGS = 0x00002000;
|
||||
Loading…
Add table
Add a link
Reference in a new issue