mirror of
https://github.com/openharmony/third_party_rust_libloading.git
synced 2026-07-19 13:16:19 -04:00
Review documentation
This commit is contained in:
+73
-19
@@ -1,29 +1,79 @@
|
||||
//! Project changelog
|
||||
//! The change log.
|
||||
|
||||
/// Release 0.7.0 (2021-01-31)
|
||||
///
|
||||
/// ## Breaking changes
|
||||
///
|
||||
/// Most importantly, a number of associated methods involved in loading a library have been marked
|
||||
/// `unsafe`. As described in the [issue #86], when loading a library the loader will execute code
|
||||
/// that's part of the dynamic library initialization routines. This is effectively equivalent to
|
||||
/// calling an arbitrary set of FFI functions and is, therefore, `unsafe`. The affected functions
|
||||
/// are: [`Library::new`], [`os::unix::Library::new`], [`os::unix::Library::open`],
|
||||
/// [`os::windows::Library::new`], [`os::windows::Library::load_with_flags`].
|
||||
/// ### Loading functions are now `unsafe`
|
||||
///
|
||||
/// `Error::LoadLibraryW` renamed to [`Error::LoadLibraryExW`] to more accurately represent the
|
||||
/// underlying API that's failing.
|
||||
/// A number of associated methods involved in loading a library were changed to
|
||||
/// be `unsafe`. The affected functions are: [`Library::new`], [`os::unix::Library::new`],
|
||||
/// [`os::unix::Library::open`], [`os::windows::Library::new`],
|
||||
/// [`os::windows::Library::load_with_flags`]. This is the most prominent breaking change in this
|
||||
/// release and affects majority of the users of `libloading`.
|
||||
///
|
||||
/// In order to see why it was necessary, consider the following snippet of C++ code:
|
||||
///
|
||||
/// ```c++
|
||||
/// #include <vector>
|
||||
/// #include <iostream>
|
||||
///
|
||||
/// static std::vector<unsigned int> UNSHUU = { 1, 2, 3 };
|
||||
///
|
||||
/// int main() {
|
||||
/// std::cout << UNSHUU[0] << UNSHUU[1] << UNSHUU[2] << std::endl; // Prints 123
|
||||
/// return 0;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The `std::vector` type, much like in Rust's `Vec`, stores its contents in a buffer allocated on
|
||||
/// the heap. In this example the vector object itself is stored and initialized as a static
|
||||
/// variable – a compile time construct. The heap, on the other hand, is a runtime construct. And
|
||||
/// yet the code works exactly as you'd expect – the vector contains numbers 1, 2 and 3 stored in
|
||||
/// a buffer on heap. So, _what_ makes it work out, exactly?
|
||||
///
|
||||
/// Various executable and shared library formats define conventions and machinery to execute
|
||||
/// arbitrary code when a program or a shared library is loaded. On systems using the PE format
|
||||
/// (e.g. Windows) this is available via the optional `DllMain` initializer. Various systems
|
||||
/// utilizing the ELF format take a sightly different approach of maintaining an array of function
|
||||
/// pointers in the `.init_array` section. A very similar mechanism exists on systems that utilize
|
||||
/// the Mach-O format.
|
||||
///
|
||||
/// For the C++ program above, the object stored in the `UNSHUU` global variable is constructed
|
||||
/// by code run as part of such an initializer routine. This initializer is run before the entry
|
||||
/// point (the `main` function) is executed, allowing for this magical behaviour to be possible.
|
||||
/// Were the C++ code built as a shared library instead, the initialization routines would run as
|
||||
/// the resulting shared library is loaded. In case of `libloading` – during the call to
|
||||
/// `Library::new` and other methods affected by this change.
|
||||
///
|
||||
/// These initialization (and very closely related termination) routines can be utilized outside of
|
||||
/// C++ too. Anybody can build a shared library in variety of different programming languages and
|
||||
/// set up the initializers to execute arbitrary code. Potentially code that does all sorts of
|
||||
/// wildly unsound stuff.
|
||||
///
|
||||
/// The routines are executed by components that are an integral part of the operating system.
|
||||
/// Changing or controlling the operation of these components is infeasible. With that in
|
||||
/// mind, the initializer and termination routines are something anybody loading a library must
|
||||
/// carefully evaluate the libraries loaded for soundness.
|
||||
///
|
||||
/// In practice, a vast majority of the libraries can be considered a good citizen and their
|
||||
/// initialization and termination routines, if they have any at all, can be trusted to be sound.
|
||||
///
|
||||
/// Also see: [issue #86].
|
||||
///
|
||||
/// ### Better & more consistent default behaviour on UNIX systems
|
||||
///
|
||||
/// On UNIX systems the [`Library::new`], [`os::unix::Library::new`] and
|
||||
/// [`os::unix::Library::this`] methods have been changed to use
|
||||
/// <code>[`RTLD_LAZY`] | [`RTLD_LOCAL`]</code> as the default set of loader options. This has a
|
||||
/// couple benefits. Namely:
|
||||
/// <code>[RTLD_LAZY] | [RTLD_LOCAL]</code> as the default set of loader options (previously:
|
||||
/// [`RTLD_NOW`]). This has a couple benefits. Namely:
|
||||
///
|
||||
/// * Lazy binding is generally quicker to execute when only a subset of symbols from a library are
|
||||
/// used and is typically the default when neither `RTLD_LAZY` nor `RTLD_NOW` are specified;
|
||||
/// * On most UNIX systems (macOS being a notable exception) [`RTLD_LOCAL`] is the default when
|
||||
/// neither `RTLD_LOCAL` nor [`RTLD_GLOBAL`] are specified. Setting the `RTLD_LOCAL` flag makes
|
||||
/// the behaviour more consistent across platforms.
|
||||
/// used and is typically the default when neither `RTLD_LAZY` nor `RTLD_NOW` are specified when
|
||||
/// calling the underlying `dlopen` API;
|
||||
/// * On most UNIX systems (macOS being a notable exception) `RTLD_LOCAL` is the default when
|
||||
/// neither `RTLD_LOCAL` nor [`RTLD_GLOBAL`] are specified. The explicit setting of the
|
||||
/// `RTLD_LOCAL` flag makes this behaviour consistent across platforms.
|
||||
///
|
||||
/// ### Dropped support for Windows XP/Vista
|
||||
///
|
||||
@@ -32,10 +82,14 @@
|
||||
/// project](https://github.com/rust-lang/compiler-team/issues/378) but also as an acknowledgement
|
||||
/// to the fact that `libloading` never worked in these environments anyway.
|
||||
///
|
||||
/// ### More accurate error variant names
|
||||
///
|
||||
/// Finally, the `Error::LoadLibraryW` renamed to [`Error::LoadLibraryExW`] to more accurately
|
||||
/// represent the underlying API that's failing. No functional changes as part of this rename
|
||||
/// intended.
|
||||
///
|
||||
/// [issue #86]: https://github.com/nagisa/rust_libloading/issues/86
|
||||
/// [`Library::new`]: crate::Library::new
|
||||
/// [windows_open]: crate::os::windows::Library::load_with_flags
|
||||
/// [unix_open]: crate::os::unix::Library::open
|
||||
/// [`Error::LoadLibraryExW`]: crate::Error::LoadLibraryExW
|
||||
/// [`os::unix::Library::this`]: crate::os::unix::Library::this
|
||||
/// [`os::unix::Library::new`]: crate::os::unix::Library::new
|
||||
@@ -43,8 +97,8 @@
|
||||
/// [`os::windows::Library::new`]: crate::os::windows::Library::new
|
||||
/// [`os::windows::Library::load_with_flags`]: crate::os::windows::Library::load_with_flags
|
||||
/// [`RTLD_NOW`]: crate::os::unix::RTLD_NOW
|
||||
/// [`RTLD_LAZY`]: crate::os::unix::RTLD_LAZY
|
||||
/// [`RTLD_LOCAL`]: crate::os::unix::RTLD_LOCAL
|
||||
/// [RTLD_LAZY]: crate::os::unix::RTLD_LAZY
|
||||
/// [RTLD_LOCAL]: crate::os::unix::RTLD_LOCAL
|
||||
/// [`RTLD_GLOBAL`]: crate::os::unix::RTLD_GLOBAL
|
||||
pub mod r0_7_0 {}
|
||||
|
||||
|
||||
+42
-56
@@ -1,15 +1,14 @@
|
||||
//! A memory-safer wrapper around system dynamic library loading primitives.
|
||||
//!
|
||||
//! Using this library allows loading [dynamic libraries](struct.Library.html) (also known as
|
||||
//! shared libraries) as well as use functions and static variables these libraries contain.
|
||||
//! shared libraries) and use functions & global variables contained within the libraries.
|
||||
//!
|
||||
//! While the library does expose a cross-platform interface to load a library and find stuff
|
||||
//! inside it, little is done to paper over the platform differences, especially where library
|
||||
//! loading is involved. The documentation for each function will attempt to document such
|
||||
//! differences on the best-effort basis.
|
||||
//! `libloading` crate exposes a cross-platform interface to load a library and utilize its
|
||||
//! contents, but little is done to paper over the differences in behaviour between different
|
||||
//! platforms. The API documentation strives to document such differences on the best-effort basis.
|
||||
//!
|
||||
//! Less safe, platform specific bindings are also available. See the
|
||||
//! [`os::platform`](os/index.html) module for details.
|
||||
//! Platform specific APIs are also available in the [`os`](crate::os) module. These APIs are more
|
||||
//! flexible but less safe.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
@@ -17,25 +16,23 @@
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! libloading = "0.6"
|
||||
//! libloading = "0.7"
|
||||
//! ```
|
||||
//!
|
||||
//! Then inside your project
|
||||
//! Then inside your code:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! extern crate libloading as lib;
|
||||
//!
|
||||
//! fn call_dynamic() -> Result<u32, Box<dyn std::error::Error>> {
|
||||
//! unsafe {
|
||||
//! let lib = lib::Library::new("/path/to/liblibrary.so")?;
|
||||
//! let func: lib::Symbol<unsafe extern fn() -> u32> = lib.get(b"my_func")?;
|
||||
//! let lib = libloading::Library::new("/path/to/liblibrary.so")?;
|
||||
//! let func: libloading::Symbol<unsafe extern fn() -> u32> = lib.get(b"my_func")?;
|
||||
//! Ok(func())
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! The compiler will ensure that the loaded `function` will not outlive the `Library` it comes
|
||||
//! from, preventing a common cause of undefined behaviour and memory safety problems.
|
||||
//! from, preventing a common class of issues.
|
||||
#![deny(
|
||||
missing_docs,
|
||||
clippy::all,
|
||||
@@ -76,24 +73,24 @@ impl Library {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When a library is loaded initializers contained within the library are executed. For the
|
||||
/// purposes of soundness, execution of these initializers is conceptually the same calling a
|
||||
/// FFI function and may impose whatever requirements on the caller.
|
||||
/// When a library is loaded initialization routines contained within the library are executed.
|
||||
/// For the purposes of safety, 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.
|
||||
///
|
||||
/// # Thread-safety
|
||||
///
|
||||
/// The implementation strives to be as MT-safe as sanely possible, however due to certain
|
||||
/// error-handling related resources not always being safe, this library is not MT-safe either.
|
||||
/// The implementation strives to be as MT-safe as sanely possible, however on certain
|
||||
/// platforms the underlying error-handling related APIs not always MT-safe. This library
|
||||
/// shares these limitations on those platforms. In particular, on certain UNIX targets
|
||||
/// `dlerror` is not MT-safe, resulting in garbage error messages in certain MT-scenarios.
|
||||
///
|
||||
/// * On Windows Vista and earlier error handling falls back to [`SetErrorMode`], which is not
|
||||
/// MT-safe. MT-scenarios involving this function may cause a traditional data race;
|
||||
/// * On some UNIX targets `dlerror` might not be MT-safe, resulting in garbage error messages
|
||||
/// in certain MT-scenarios.
|
||||
///
|
||||
/// [`SetErrorMode`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx
|
||||
///
|
||||
/// Calling this function from multiple threads is not safe if used in conjunction with
|
||||
/// relative filenames and the library search path is modified (`SetDllDirectory` function on
|
||||
/// Calling this function from multiple threads is not MT-safe if used in conjunction with
|
||||
/// library filenames and the library search path is modified (`SetDllDirectory` function on
|
||||
/// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX).
|
||||
///
|
||||
/// # Platform-specific behaviour
|
||||
@@ -103,15 +100,8 @@ impl Library {
|
||||
/// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods
|
||||
/// for further information on library lookup behaviour.
|
||||
///
|
||||
/// ## Windows
|
||||
///
|
||||
/// If the `filename` specifies a library filename without path and with extension omitted,
|
||||
/// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
|
||||
/// trailing `.` to the `filename`.
|
||||
///
|
||||
/// If the library contains thread local variables (MSVC’s `_declspec(thread)`, Rust’s
|
||||
/// `#[thread_local]` attributes), loading the library will fail on versions prior to Windows
|
||||
/// Vista.
|
||||
/// `.dll` extension is implicitly added on Windows.
|
||||
///
|
||||
/// # Tips
|
||||
///
|
||||
@@ -141,26 +131,25 @@ impl Library {
|
||||
|
||||
/// Get a pointer to function or static variable by symbol name.
|
||||
///
|
||||
/// The `symbol` may not contain any null bytes, with an exception of last byte. A null
|
||||
/// terminated `symbol` may avoid a string allocation in some cases.
|
||||
/// The `symbol` may not contain any null bytes, with an exception of 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
|
||||
///
|
||||
/// Pointer to a value of arbitrary type is returned. Using a value with wrong type is
|
||||
/// undefined.
|
||||
/// 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 these
|
||||
/// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems or
|
||||
/// Windows.
|
||||
/// 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 the underlying `dlsym` call
|
||||
/// returns a null pointer. There are rare situations where `dlsym` returns a genuine null
|
||||
/// 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 [`os::unix::Library::get_singlethreaded`] call.
|
||||
///
|
||||
@@ -242,15 +231,12 @@ unsafe impl Sync for Library {}
|
||||
/// Symbol from a library.
|
||||
///
|
||||
/// This type is a safeguard against using dynamically loaded symbols after a `Library` is
|
||||
/// unloaded. Primary method to create an instance of a `Symbol` is via `Library::get`.
|
||||
/// unloaded. Primary method to create an instance of a `Symbol` is via [`Library::get`].
|
||||
///
|
||||
/// Due to implementation of the `Deref` trait, an instance of `Symbol` may be used as if it was a
|
||||
/// function or variable directly, without taking care to “extract” function or variable manually
|
||||
/// most of the time.
|
||||
/// The `Deref` trait implementation allows use of `Symbol` as if it was a function or variable
|
||||
/// itself, without taking care to “extract” function or variable manually most of the time.
|
||||
///
|
||||
/// See [`Library::get`] for details.
|
||||
///
|
||||
/// [`Library::get`]: ./struct.Library.html#method.get
|
||||
/// [`Library::get`]: Library::get
|
||||
pub struct Symbol<'lib, T: 'lib> {
|
||||
inner: imp::Symbol<T>,
|
||||
pd: marker::PhantomData<&'lib T>
|
||||
@@ -282,12 +268,11 @@ impl<'lib, T> Symbol<'lib, T> {
|
||||
/// Wrap the `os::platform::Symbol` into this safe wrapper.
|
||||
///
|
||||
/// Note that, in order to create association between the symbol and the library this symbol
|
||||
/// came from, this function requires reference to the library provided.
|
||||
/// came from, this function requires a reference to the library.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is invalid to provide a reference to any other value other than the library the `sym`
|
||||
/// was loaded from. Doing so invalidates any lifetime guarantees.
|
||||
/// The `library` reference must be exactly the library `sym` was loaded from.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -300,7 +285,8 @@ impl<'lib, T> Symbol<'lib, T> {
|
||||
/// let symbol = Symbol::from_raw(symbol, &lib);
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn from_raw<L>(sym: imp::Symbol<T>, _: &'lib L) -> Symbol<'lib, T> {
|
||||
pub unsafe fn from_raw<L>(sym: imp::Symbol<T>, library: &'lib L) -> Symbol<'lib, T> {
|
||||
let _ = library; // ignore here for documentation purposes.
|
||||
Symbol {
|
||||
inner: sym,
|
||||
pd: marker::PhantomData
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//! Unsafe, platform specific bindings to dynamic library loading facilities.
|
||||
//! Unsafe but flexible platform specific bindings to dynamic library loading facilities.
|
||||
//!
|
||||
//! These modules expose more extensive, powerful, less principled bindings to the dynamic
|
||||
//! library loading facilities. Use of these bindings come at the cost of less (in most cases,
|
||||
|
||||
+38
-28
@@ -103,21 +103,26 @@ impl Library {
|
||||
/// a file. Otherwise, platform-specific algorithms are employed to find a library with a
|
||||
/// matching file name.
|
||||
///
|
||||
/// This is equivalent to [`Library::open`]`(filename, RTLD_LAZY | RTLD_LOCAL)`.
|
||||
/// 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 initializers contained within the library are executed. For the
|
||||
/// purposes of soundness, execution of these initializers is conceptually the same calling a
|
||||
/// FFI function and may impose whatever requirements on the caller.
|
||||
/// When a library is loaded initialization routines contained within the library are executed.
|
||||
/// For the purposes of safety, 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)
|
||||
}
|
||||
|
||||
/// Eagerly load the `Library` representing the current executable.
|
||||
/// Load the `Library` representing the current executable.
|
||||
///
|
||||
/// [`Library::get`] calls of the returned `Library` will look for symbols in following
|
||||
/// locations in order:
|
||||
@@ -130,13 +135,14 @@ impl Library {
|
||||
/// Note that behaviour of `Library` loaded with this method is different from
|
||||
/// Libraries loaded with [`os::windows::Library::this`].
|
||||
///
|
||||
/// This is equivalent to [`Library::open`]`(None, RTLD_LAZY | RTLD_LOCAL)`.
|
||||
/// 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 obtains a handle to an existing, loaded module, no danger in
|
||||
// SAFE: this does not load any new shared library images, no danger in it executing
|
||||
// initializer routines.
|
||||
Library::open(None::<&OsStr>, RTLD_LAZY | RTLD_LOCAL).expect("this should never fail")
|
||||
}
|
||||
}
|
||||
@@ -150,9 +156,14 @@ impl Library {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When a library is loaded initializers contained within the library are executed. For the
|
||||
/// purposes of soundness, execution of these initializers is conceptually the same calling a
|
||||
/// FFI function and may impose whatever requirements on the caller.
|
||||
/// When a library is loaded initialization routines contained within the library are executed.
|
||||
/// For the purposes of safety, 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 {
|
||||
@@ -208,28 +219,27 @@ impl Library {
|
||||
|
||||
/// Get a pointer to function or static variable by symbol name.
|
||||
///
|
||||
/// The `symbol` may not contain any null bytes, with an exception of last byte. A null
|
||||
/// terminated `symbol` may avoid an allocation in some cases.
|
||||
/// The `symbol` may not contain any null bytes, with an exception of 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
|
||||
///
|
||||
/// This function does not validate the type `T`. It is up to the user of this function to
|
||||
/// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no
|
||||
/// defined behaviour.
|
||||
/// 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 these
|
||||
/// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems.
|
||||
/// 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 symbol at null address is something you
|
||||
/// care about, consider using the [`Library::get_singlethreaded`] call.
|
||||
/// 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;
|
||||
@@ -255,17 +265,16 @@ impl Library {
|
||||
|
||||
/// Get a pointer to function or static variable by symbol name.
|
||||
///
|
||||
/// The `symbol` may not contain any null bytes, with an exception of last byte. A null
|
||||
/// terminated `symbol` may avoid a string allocation in some cases.
|
||||
/// The `symbol` may not contain any null bytes, with an exception of 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
|
||||
///
|
||||
/// This function does not validate the type `T`. It is up to the user of this function to
|
||||
/// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no
|
||||
/// defined behaviour.
|
||||
/// Users of this API must specify the correct type of the function or variable loaded. Using a
|
||||
/// `Symbol` with a wrong type is undefined.
|
||||
///
|
||||
/// It is up to the user of this library to ensure that no other calls to an MT-unsafe
|
||||
/// implementation of `dlerror` occur during execution of this function. Failing that, the
|
||||
@@ -273,8 +282,8 @@ impl Library {
|
||||
///
|
||||
/// # Platform-specific behaviour
|
||||
///
|
||||
/// Implementation of thread local variables is extremely platform specific and uses of these
|
||||
/// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems.
|
||||
/// 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 {
|
||||
@@ -312,7 +321,8 @@ impl Library {
|
||||
/// 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 this will be done when `Library` is dropped.
|
||||
/// 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> {
|
||||
@@ -324,7 +334,7 @@ impl Library {
|
||||
}
|
||||
}).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 `FreeLibrary` again. only
|
||||
// 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
|
||||
|
||||
+21
-12
@@ -86,15 +86,20 @@ impl Library {
|
||||
/// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
|
||||
/// trailing `.` to the `filename`.
|
||||
///
|
||||
/// This is equivalent to [`Library::load_with_flags`]`(filename, 0)`.
|
||||
/// 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 initializers contained within the library are executed. For the
|
||||
/// purposes of soundness, execution of these initializers is conceptually the same calling a
|
||||
/// FFI function and may impose whatever requirements on the caller.
|
||||
/// When a library is loaded initialization routines contained within the library are executed.
|
||||
/// For the purposes of safety, 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)
|
||||
@@ -173,9 +178,14 @@ impl Library {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When a library is loaded initializers contained within the library are executed. For the
|
||||
/// purposes of soundness, execution of these initializers is conceptually the same calling a
|
||||
/// FFI function and may impose whatever requirements on the caller.
|
||||
/// When a library is loaded initialization routines contained within the library are executed.
|
||||
/// For the purposes of safety, 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: DWORD) -> Result<Library, crate::Error> {
|
||||
let wide_filename: Vec<u16> = filename.as_ref().encode_wide().chain(Some(0)).collect();
|
||||
let _guard = ErrorModeGuard::new();
|
||||
@@ -206,9 +216,8 @@ impl Library {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function does not validate the type `T`. It is up to the user of this function to
|
||||
/// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no
|
||||
/// definied behaviour.
|
||||
/// Users of this API must specify the correct type of the function or variable loaded. Using a
|
||||
/// `Symbol` with a wrong type is undefined.
|
||||
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)?;
|
||||
@@ -229,8 +238,8 @@ impl Library {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Pointer to a value of arbitrary type is returned. Using a value with wrong type is
|
||||
/// undefined.
|
||||
/// Users of this API must specify the correct type of the function or variable loaded. Using a
|
||||
/// `Symbol` with a wrong type is undefined.
|
||||
pub unsafe fn get_ordinal<T>(&self, ordinal: WORD) -> Result<Symbol<T>, crate::Error> {
|
||||
ensure_compatible_types::<T, FARPROC>()?;
|
||||
with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
|
||||
|
||||
Reference in New Issue
Block a user