aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-03-23 19:28:00 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-03-23 19:28:00 +0000
commita8ec863d3b317e190276ec8ca23c194b1f452faa (patch)
tree8167ff3ef81634a34f22347866ca7517ab5783d0
parentd1f844e7e2f269c54b4b575d822ba645aa1986bb (diff)
parent73c4575102810719045f83ebb0f5922735710a66 (diff)
downloadlibloading-a8ec863d3b317e190276ec8ca23c194b1f452faa.tar.gz
Snap for 8346178 from 73c4575102810719045f83ebb0f5922735710a66 to simpleperf-release
Change-Id: I461c1052fc32f77eef54e283d56b573aeca4e1fc
-rw-r--r--.cargo_vcs_info.json7
-rw-r--r--.github/workflows/libloading.yml24
-rw-r--r--Android.bp2
-rw-r--r--Cargo.toml16
-rw-r--r--Cargo.toml.orig9
-rw-r--r--METADATA12
-rw-r--r--README.mkd7
-rw-r--r--src/changelog.rs42
-rw-r--r--src/lib.rs342
-rw-r--r--src/os/mod.rs12
-rw-r--r--src/os/unix/consts.rs8
-rw-r--r--src/os/unix/mod.rs52
-rw-r--r--src/os/windows/mod.rs70
-rw-r--r--src/safe.rs299
-rw-r--r--src/util.rs15
-rw-r--r--tests/constants.rs2
-rw-r--r--tests/functions.rs4
17 files changed, 479 insertions, 444 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 69cdb18..dfc0076 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@
{
"git": {
- "sha1": "7fbd3a34336f7839bdd6d6aaf83a9a763c4fa1e5"
- }
-}
+ "sha1": "00c21d873aeeac16935ac85962486b41776fe976"
+ },
+ "path_in_vcs": ""
+} \ No newline at end of file
diff --git a/.github/workflows/libloading.yml b/.github/workflows/libloading.yml
index 811681d..e7e84ac 100644
--- a/.github/workflows/libloading.yml
+++ b/.github/workflows/libloading.yml
@@ -26,37 +26,28 @@ jobs:
profile: minimal
components: clippy
default: true
- - name: Update
- uses: actions-rs/cargo@v1
- with:
- command: update
- args: --manifest-path=Cargo.toml
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
- - name: Build
- uses: actions-rs/cargo@v1
- with:
- command: build
- args: --manifest-path=Cargo.toml
- name: Test
uses: actions-rs/cargo@v1
with:
command: test
- args: --manifest-path=Cargo.toml -- --nocapture
+ args: -- --nocapture
- name: Test Release
uses: actions-rs/cargo@v1
with:
command: test
- args: --manifest-path=Cargo.toml --release -- --nocapture
+ args: --release -- --nocapture
- name: Documentation
uses: actions-rs/cargo@v1
with:
- command: doc
- args: --manifest-path=Cargo.toml
- env:
- RUSTDOCFLAGS: --cfg docsrs
+ command: rustdoc
+ args: |
+ -Zunstable-options
+ --config
+ 'build.rustdogflags=["--cfg", "libloading_docs", "-D", "rustdoc::broken_intra_doc_links"]'
if: ${{ matrix.rust_toolchain == 'nightly' }}
windows-gnu-test:
@@ -110,6 +101,7 @@ jobs:
- x86_64-unknown-openbsd
- x86_64-unknown-redox
- x86_64-fuchsia
+ - wasm32-unknown-unknown
timeout-minutes: 20
steps:
- uses: actions/checkout@v2
diff --git a/Android.bp b/Android.bp
index ffc103e..bdf4513 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,7 +23,7 @@ rust_library {
host_supported: true,
crate_name: "libloading",
cargo_env_compat: true,
- cargo_pkg_version: "0.7.0",
+ cargo_pkg_version: "0.7.3",
srcs: ["src/lib.rs"],
edition: "2015",
rustlibs: [
diff --git a/Cargo.toml b/Cargo.toml
index 396a5c2..39b41f3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,18 +3,18 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
[package]
+rust-version = "1.40.0"
name = "libloading"
-version = "0.7.0"
+version = "0.7.3"
authors = ["Simonas Kazlauskas <libloading@kazlauskas.me>"]
-description = "A safer binding to platform’s dynamic library loading utilities"
+description = "Bindings around the platform's dynamic library loading primitives with greatly improved memory safety."
documentation = "https://docs.rs/libloading/"
readme = "README.mkd"
keywords = ["dlopen", "load", "shared", "dylib"]
@@ -23,7 +23,7 @@ license = "ISC"
repository = "https://github.com/nagisa/rust_libloading/"
[package.metadata.docs.rs]
all-features = true
-rustdoc-args = ["--cfg", "docsrs"]
+rustdoc-args = ["--cfg", "libloading_docs"]
[dev-dependencies.libc]
version = "0.2"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index d946299..35e8353 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -2,16 +2,17 @@
name = "libloading"
# When bumping
# * Don’t forget to add an entry to `src/changelog.rs`
-# * If bumping a incompatible version, adjust documentation in `src/lib.rs`
-version = "0.7.0"
+# * If bumping to an incompatible version, adjust the documentation in `src/lib.rs`
+version = "0.7.3"
authors = ["Simonas Kazlauskas <libloading@kazlauskas.me>"]
license = "ISC"
repository = "https://github.com/nagisa/rust_libloading/"
documentation = "https://docs.rs/libloading/"
readme = "README.mkd"
-description = "A safer binding to platform’s dynamic library loading utilities"
+description = "Bindings around the platform's dynamic library loading primitives with greatly improved memory safety."
keywords = ["dlopen", "load", "shared", "dylib"]
categories = ["api-bindings"]
+rust-version = "1.40.0"
[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
@@ -29,4 +30,4 @@ static_assertions = "1.1"
[package.metadata.docs.rs]
all-features = true
-rustdoc-args = ["--cfg", "docsrs"]
+rustdoc-args = ["--cfg", "libloading_docs"]
diff --git a/METADATA b/METADATA
index 769af4a..0efb20d 100644
--- a/METADATA
+++ b/METADATA
@@ -1,5 +1,5 @@
name: "libloading"
-description: "A safer binding to platform\'s dynamic library loading utilities"
+description: "Bindings around the platform\'s dynamic library loading primitives with greatly improved memory safety."
third_party {
url {
type: HOMEPAGE
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/libloading/libloading-0.7.0.crate"
+ value: "https://static.crates.io/crates/libloading/libloading-0.7.3.crate"
}
- version: "0.7.0"
+ version: "0.7.3"
license_type: NOTICE
last_upgrade_date {
- year: 2021
- month: 2
- day: 9
+ year: 2022
+ month: 3
+ day: 1
}
}
diff --git a/README.mkd b/README.mkd
index 8f7d342..66abb30 100644
--- a/README.mkd
+++ b/README.mkd
@@ -1,11 +1,8 @@
# libloading
-Safer bindings around system dynamic library loading primitives. The most important safety
-guarantee by this library is prevention of dangling-`Symbol`s that may occur after a `Library` is
-unloaded.
+Bindings around the platform's dynamic library loading primitives with greatly improved memory safety. The most important safety guarantee of this library is the prevention of dangling `Symbol`s that may occur after a `Library` is unloaded.
-Using this library allows loading dynamic libraries (also known as shared libraries) as well as use
-functions and static variables these libraries contain.
+Using this library allows the loading of dynamic libraries, also known as shared libraries, as well as the use of the functions and static variables that these libraries may contain.
* [Documentation][docs]
* [Changelog][changelog]
diff --git a/src/changelog.rs b/src/changelog.rs
index c927551..f8b898e 100644
--- a/src/changelog.rs
+++ b/src/changelog.rs
@@ -1,6 +1,43 @@
//! The change log.
-/// Release 0.7.0 (2021-01-31)
+/// Release 0.7.3 (2022-01-15)
+///
+/// This release has no functional changes.
+///
+/// In this release the `docsrs` `cfg` has been renamed to `libloading_docs` to better reflect that
+/// this `cfg` is intended to be only used by `libloading` and only specifically for the invocation
+/// of `rustdoc` when documenting `libloading`. Setting this `cfg` in any other situation is
+/// unsupported and will not work.
+pub mod r0_7_3 {}
+
+/// Release 0.7.2 (2021-11-14)
+///
+/// Cargo.toml now specifies the MSRV bounds, which enables tooling to report an early failure when
+/// the version of the toolchain is insufficient. Refer to the [min-rust-version RFC] and its
+/// [tracking issue].
+///
+/// [min-rust-version RFC]: https://rust-lang.github.io/rfcs/2495-min-rust-version.html
+/// [tracking issue]: https://github.com/rust-lang/rust/issues/65262
+///
+/// Additionally, on platforms `libloading` has no support (today: `not(any(unix, windows))`), we
+/// will no longer attempt to implement the cross-platform `Library` and `Symbol` types. This makes
+/// `libloading` compile on targets such as `wasm32-unknown-unknown` and gives ability to the
+/// downstream consumers of this library to decide how they want to handle the absence of the
+/// library loading implementation in their code. One of such approaches could be depending on
+/// `libloading` itself optionally as such:
+///
+/// ```toml
+/// [target.'cfg(any(unix, windows))'.dependencies.libloading]
+/// version = "0.7"
+/// ```
+pub mod r0_7_2 {}
+
+/// Release 0.7.1 (2021-10-09)
+///
+/// Significantly improved the consistency and style of the documentation.
+pub mod r0_7_1 {}
+
+/// Release 0.7.0 (2021-02-06)
///
/// ## Breaking changes
///
@@ -187,7 +224,6 @@ pub mod r0_6_1 {}
/// [`Error`]: crate::Error
pub mod r0_6_0 {}
-
/// Release 0.5.2 (2019-07-07)
///
/// * Added API to convert OS-specific `Library` and `Symbol` conversion to underlying resources.
@@ -218,7 +254,6 @@ pub mod r0_5_0 {}
/// * `cargo test --release` now works when testing libloading.
pub mod r0_4_3 {}
-
/// Release 0.4.2 (2017-09-24)
///
/// * Improved error and race-condition handling on Windows;
@@ -226,7 +261,6 @@ pub mod r0_4_3 {}
/// * Added `Symbol::<Option<T>::lift_option() -> Option<Symbol<T>>` convenience method.
pub mod r0_4_2 {}
-
/// Release 0.4.1 (2017-08-29)
///
/// * Solaris support
diff --git a/src/lib.rs b/src/lib.rs
index 9a531f1..6f0e4cb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,25 +1,27 @@
-//! A memory-safer wrapper around system dynamic library loading primitives.
+//! Bindings around the platform's dynamic library loading primitives with greatly improved memory safety.
//!
-//! Using this library allows loading [dynamic libraries](struct.Library.html) (also known as
-//! shared libraries) and use functions & global variables contained within the libraries.
+//! Using this library allows the loading of [dynamic libraries](struct.Library.html), also known as
+//! shared libraries, and the use of the functions and static variables they contain.
//!
-//! `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.
+//! The `libloading` crate exposes a cross-platform interface to load a library and make use of its
+//! contents, but little is done to hide the differences in behaviour between platforms.
+//! The API documentation strives to document such differences as much as possible.
//!
-//! Platform specific APIs are also available in the [`os`](crate::os) module. These APIs are more
-//! flexible but less safe.
+//! Platform-specific APIs are also available in the [`os`](crate::os) module. These APIs are more
+//! flexible, but less safe.
//!
-//! # Usage
+//! # Installation
//!
-//! Add a dependency on this library to your `Cargo.toml`:
+//! Add the `libloading` library to your dependencies in `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! libloading = "0.7"
//! ```
//!
-//! Then inside your code:
+//! # Usage
+//!
+//! In your code, run the following:
//!
//! ```no_run
//! fn call_dynamic() -> Result<u32, Box<dyn std::error::Error>> {
@@ -31,319 +33,29 @@
//! }
//! ```
//!
-//! The compiler will ensure that the loaded `function` will not outlive the `Library` it comes
-//! from, preventing a common class of issues.
-#![deny(
- missing_docs,
- clippy::all,
- unreachable_pub,
- unused,
-)]
-#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
-#![cfg_attr(docsrs, feature(doc_cfg))]
-
-use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
-use std::ffi::{OsStr, OsString};
-use std::fmt;
-use std::ops;
-use std::marker;
+//! The compiler will ensure that the loaded function will not outlive the `Library` from which it comes,
+//! preventing the most common memory-safety issues.
+#![cfg_attr(any(unix, windows), deny(missing_docs, clippy::all, unreachable_pub, unused))]
+#![cfg_attr(libloading_docs, feature(doc_cfg))]
-#[cfg(unix)]
-use self::os::unix as imp;
-#[cfg(windows)]
-use self::os::windows as imp;
-pub use self::error::Error;
-
-pub mod os;
pub mod changelog;
+pub mod os;
mod util;
-mod error;
-/// A loaded dynamic library.
-pub struct Library(imp::Library);
-
-impl Library {
- /// Find and load a dynamic library.
- ///
- /// The `filename` argument may be any of:
- ///
- /// * A library filename;
- /// * Absolute path to the library;
- /// * Relative (to the current working directory) path to the library.
- ///
- /// # Safety
- ///
- /// 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 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.
- ///
- /// 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
- ///
- /// When a plain library filename is supplied, locations where library is searched for is
- /// platform specific and cannot be adjusted in a portable manner. See documentation for
- /// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods
- /// for further information on library lookup behaviour.
- ///
- /// If the `filename` specifies a library filename without path and with extension omitted,
- /// `.dll` extension is implicitly added on Windows.
- ///
- /// # Tips
- ///
- /// Distributing your dynamic libraries under a filename common to all platforms (e.g.
- /// `awesome.module`) allows to avoid code which has to account for platform’s conventional
- /// library filenames.
- ///
- /// Strive to specify an absolute or at least a relative path to your library, unless
- /// system-wide libraries are being loaded. Platform-dependent library search locations
- /// combined with various quirks related to path-less filenames may cause flakiness in
- /// programs.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// # use ::libloading::Library;
- /// // Any of the following are valid.
- /// unsafe {
- /// let _ = Library::new("/path/to/awesome.module").unwrap();
- /// let _ = Library::new("../awesome.module").unwrap();
- /// let _ = Library::new("libsomelib.so.1").unwrap();
- /// }
- /// ```
- pub unsafe fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, Error> {
- imp::Library::new(filename).map(From::from)
- }
-
- /// 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. 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 [`os::unix::Library::get_singlethreaded`] call.
- ///
- /// # Examples
- ///
- /// Given a loaded library:
- ///
- /// ```no_run
- /// # use ::libloading::Library;
- /// let lib = unsafe {
- /// Library::new("/path/to/awesome.module").unwrap()
- /// };
- /// ```
- ///
- /// Loading and using a function looks like this:
- ///
- /// ```no_run
- /// # use ::libloading::{Library, Symbol};
- /// # let lib = unsafe {
- /// # Library::new("/path/to/awesome.module").unwrap()
- /// # };
- /// unsafe {
- /// let awesome_function: Symbol<unsafe extern fn(f64) -> f64> =
- /// lib.get(b"awesome_function\0").unwrap();
- /// awesome_function(0.42);
- /// }
- /// ```
- ///
- /// A static variable may also be loaded and inspected:
- ///
- /// ```no_run
- /// # use ::libloading::{Library, Symbol};
- /// # let lib = unsafe { Library::new("/path/to/awesome.module").unwrap() };
- /// unsafe {
- /// let awesome_variable: Symbol<*mut f64> = lib.get(b"awesome_variable\0").unwrap();
- /// **awesome_variable = 42.0;
- /// };
- /// ```
- pub unsafe fn get<'lib, T>(&'lib self, symbol: &[u8]) -> Result<Symbol<'lib, T>, Error> {
- self.0.get(symbol).map(|from| Symbol::from_raw(from, self))
- }
-
- /// 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<(), Error> {
- self.0.close()
- }
-}
-
-impl fmt::Debug for Library {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-impl From<imp::Library> for Library {
- fn from(lib: imp::Library) -> Library {
- Library(lib)
- }
-}
-
-impl From<Library> for imp::Library {
- fn from(lib: Library) -> imp::Library {
- lib.0
- }
-}
-
-unsafe impl Send for Library {}
-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`].
-///
-/// 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.
-///
-/// [`Library::get`]: Library::get
-pub struct Symbol<'lib, T: 'lib> {
- inner: imp::Symbol<T>,
- pd: marker::PhantomData<&'lib T>
-}
-
-impl<'lib, T> Symbol<'lib, T> {
- /// Extract the wrapped `os::platform::Symbol`.
- ///
- /// # Safety
- ///
- /// Using this function relinquishes all the lifetime guarantees. It is up to programmer to
- /// ensure the resulting `Symbol` is not used past the lifetime of the `Library` this symbol
- /// was loaded from.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// # use ::libloading::{Library, Symbol};
- /// unsafe {
- /// let lib = Library::new("/path/to/awesome.module").unwrap();
- /// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
- /// let symbol = symbol.into_raw();
- /// }
- /// ```
- pub unsafe fn into_raw(self) -> imp::Symbol<T> {
- self.inner
- }
-
- /// 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 a reference to the library.
- ///
- /// # Safety
- ///
- /// The `library` reference must be exactly the library `sym` was loaded from.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// # use ::libloading::{Library, Symbol};
- /// unsafe {
- /// let lib = Library::new("/path/to/awesome.module").unwrap();
- /// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
- /// let symbol = symbol.into_raw();
- /// let symbol = Symbol::from_raw(symbol, &lib);
- /// }
- /// ```
- 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
- }
- }
-}
-
-impl<'lib, T> Symbol<'lib, Option<T>> {
- /// Lift Option out of the symbol.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// # use ::libloading::{Library, Symbol};
- /// unsafe {
- /// let lib = Library::new("/path/to/awesome.module").unwrap();
- /// let symbol: Symbol<Option<*mut u32>> = lib.get(b"symbol\0").unwrap();
- /// let symbol: Symbol<*mut u32> = symbol.lift_option().expect("static is not null");
- /// }
- /// ```
- pub fn lift_option(self) -> Option<Symbol<'lib, T>> {
- self.inner.lift_option().map(|is| Symbol {
- inner: is,
- pd: marker::PhantomData,
- })
- }
-}
-
-impl<'lib, T> Clone for Symbol<'lib, T> {
- fn clone(&self) -> Symbol<'lib, T> {
- Symbol {
- inner: self.inner.clone(),
- pd: marker::PhantomData
- }
- }
-}
-
-// FIXME: implement FnOnce for callable stuff instead.
-impl<'lib, T> ops::Deref for Symbol<'lib, T> {
- type Target = T;
- fn deref(&self) -> &T {
- ops::Deref::deref(&self.inner)
- }
-}
+mod error;
+pub use self::error::Error;
-impl<'lib, T> fmt::Debug for Symbol<'lib, T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.inner.fmt(f)
- }
-}
+#[cfg(any(unix, windows, libloading_docs))]
+mod safe;
+#[cfg(any(unix, windows, libloading_docs))]
+pub use self::safe::{Library, Symbol};
-unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {}
-unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {}
+use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
+use std::ffi::{OsStr, OsString};
/// Converts a library name to a filename generally appropriate for use on the system.
///
-/// The function will prepend prefixes (such as `lib`) and suffixes (such as `.so`) to the library
+/// This function will prepend prefixes (such as `lib`) and suffixes (such as `.so`) to the library
/// `name` to construct the filename.
///
/// # Examples
diff --git a/src/os/mod.rs b/src/os/mod.rs
index c03ebc1..710353f 100644
--- a/src/os/mod.rs
+++ b/src/os/mod.rs
@@ -1,6 +1,6 @@
-//! Unsafe but flexible 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
+//! 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.
//!
@@ -17,11 +17,11 @@
//! ```
/// UNIX implementation of dynamic library loading.
-#[cfg(any(unix, docsrs))]
-#[cfg_attr(docsrs, doc(cfg(unix)))]
+#[cfg(any(unix, libloading_docs))]
+#[cfg_attr(libloading_docs, doc(cfg(unix)))]
pub mod unix;
/// Windows implementation of dynamic library loading.
-#[cfg(any(windows, docsrs))]
-#[cfg_attr(docsrs, doc(cfg(windows)))]
+#[cfg(any(windows, libloading_docs))]
+#[cfg_attr(libloading_docs, doc(cfg(windows)))]
pub mod windows;
diff --git a/src/os/unix/consts.rs b/src/os/unix/consts.rs
index 2c18f95..dbe4df9 100644
--- a/src/os/unix/consts.rs
+++ b/src/os/unix/consts.rs
@@ -7,7 +7,7 @@ use std::os::raw::c_int;
/// 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 behavior mimics the normal handling of process execution.
+/// execution, this behaviour mimics the normal handling of process execution.
///
/// Conflicts with [`RTLD_NOW`].
///
@@ -18,7 +18,7 @@ pub const RTLD_LAZY: c_int = posix::RTLD_LAZY;
///
/// 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 behavior may be useful for applications that need to
+/// 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.
///
@@ -43,7 +43,7 @@ pub const RTLD_GLOBAL: c_int = posix::RTLD_GLOBAL;
/// 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(docsrs, not(unix)))]
+#[cfg(all(libloading_docs, not(unix)))]
mod posix {
use super::c_int;
pub(super) const RTLD_LAZY: c_int = !0;
@@ -52,7 +52,7 @@ mod posix {
pub(super) const RTLD_LOCAL: c_int = !0;
}
-#[cfg(any(not(docsrs), unix))]
+#[cfg(any(not(libloading_docs), unix))]
mod posix {
extern crate cfg_if;
use self::cfg_if::cfg_if;
diff --git a/src/os/unix/mod.rs b/src/os/unix/mod.rs
index 45e8230..fd0777e 100644
--- a/src/os/unix/mod.rs
+++ b/src/os/unix/mod.rs
@@ -1,19 +1,18 @@
// A hack for docs.rs to build documentation that has both windows and linux documentation in the
// same rustdoc build visible.
-#[cfg(all(docsrs, not(unix)))]
-mod unix_imports {
-}
-#[cfg(any(not(docsrs), unix))]
+#[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 util::{ensure_compatible_types, cstr_cow_from_bytes};
use std::ffi::{CStr, OsStr};
-use std::{fmt, marker, mem, ptr};
use std::os::raw;
-pub use self::consts::*;
+use std::{fmt, marker, mem, ptr};
+use util::{cstr_cow_from_bytes, ensure_compatible_types};
mod consts;
@@ -109,8 +108,8 @@ impl Library {
///
/// # Safety
///
- /// 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
+ /// 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.
///
@@ -127,12 +126,12 @@ impl Library {
/// [`Library::get`] calls of the returned `Library` will look for symbols in following
/// locations in order:
///
- /// 1. Original program image;
+ /// 1. The original program image;
/// 2. Any executable object files (e.g. shared libraries) loaded at program startup;
- /// 3. Executable object files loaded at runtime (e.g. via other `Library::new` calls or via
- /// calls to the `dlopen` function)
+ /// 3. Any executable object files loaded at runtime (e.g. via other `Library::new` calls or via
+ /// calls to the `dlopen` function).
///
- /// Note that behaviour of `Library` loaded with this method is different from
+ /// 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>.
@@ -142,22 +141,22 @@ impl Library {
pub fn this() -> Library {
unsafe {
// SAFE: this does not load any new shared library images, no danger in it executing
- // initializer routines.
+ // 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 behaviour
+ /// 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 initialization routines contained within the library are executed.
- /// For the purposes of safety, execution of these routines is conceptually the same calling an
+ /// 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.
///
@@ -217,9 +216,9 @@ impl Library {
}
- /// Get a pointer to function or static variable by symbol name.
+ /// Get a pointer to a function or static variable by symbol name.
///
- /// The `symbol` may not contain any null bytes, with an exception of last byte. Providing a
+ /// 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
@@ -265,7 +264,7 @@ 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. Providing a
+ /// 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
@@ -273,16 +272,15 @@ impl Library {
///
/// # 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.
+ /// 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 execution of this function. Failing that, the
+ /// implementation of `dlerror` occur during the execution of this function. Failing that, the
/// behaviour of this function is not defined.
///
/// # Platform-specific behaviour
///
- /// Implementation of thread local variables is extremely platform specific and uses of such
+ /// 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> {
@@ -357,15 +355,15 @@ impl fmt::Debug for Library {
/// Symbol from a library.
///
-/// A major difference compared to the cross-platform `Symbol` is that this does not ensure the
-/// `Symbol` does not outlive `Library` it comes from.
+/// 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.
+ /// Convert the loaded `Symbol` into a raw pointer.
pub fn into_raw(self) -> *mut raw::c_void {
let pointer = self.pointer;
mem::forget(self);
diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs
index 7e28527..eadeb69 100644
--- a/src/os/windows/mod.rs
+++ b/src/os/windows/mod.rs
@@ -1,6 +1,6 @@
// A hack for docs.rs to build documentation that has both windows and linux documentation in the
// same rustdoc build visible.
-#[cfg(all(docsrs, not(windows)))]
+#[cfg(all(libloading_docs, not(windows)))]
mod windows_imports {
pub(super) enum WORD {}
pub(super) struct DWORD;
@@ -23,7 +23,7 @@ mod windows_imports {
pub(crate) const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = DWORD;
}
}
-#[cfg(any(not(docsrs), windows))]
+#[cfg(any(not(libloading_docs), windows))]
mod windows_imports {
extern crate winapi;
pub(super) use self::winapi::shared::minwindef::{WORD, DWORD, HMODULE, FARPROC};
@@ -55,23 +55,23 @@ use util::{ensure_compatible_types, cstr_cow_from_bytes};
use std::ffi::{OsStr, OsString};
use std::{fmt, io, marker, mem, ptr};
-/// A platform-specific counterpart of the cross-platform [`Library`](crate::Library).
+/// 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.
+// 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 the people who have seen the question) knows for
+// * 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 filled at https://connect.microsoft.com/ against Windows Server)
+// part. (NB: bugs filed at https://connect.microsoft.com/ against Windows Server)
unsafe impl Sync for Library {}
impl Library {
@@ -79,11 +79,11 @@ impl Library {
///
/// 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
+ /// 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 path and with extension omitted,
- /// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
+ /// 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>.
@@ -92,8 +92,8 @@ impl Library {
///
/// # Safety
///
- /// 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
+ /// 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.
///
@@ -107,7 +107,7 @@ impl Library {
/// Get the `Library` representing the original program executable.
///
- /// Note that behaviour of `Library` loaded with this method is different from
+ /// 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, _)`.
@@ -131,15 +131,15 @@ impl Library {
/// 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
+ /// 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 path and with extension omitted,
- /// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
+ /// 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, _)`.
@@ -169,7 +169,7 @@ impl Library {
/// Find and load a module, additionally adjusting behaviour with flags.
///
- /// See [`Library::new`] for documentation on handling of the `filename` argument. See the
+ /// 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)`.
@@ -178,8 +178,8 @@ impl Library {
///
/// # Safety
///
- /// 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
+ /// 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.
///
@@ -206,9 +206,9 @@ impl Library {
ret
}
- /// Get a pointer to function or static variable by symbol name.
+ /// Get a pointer to a function or static variable by symbol name.
///
- /// The `symbol` may not contain any null bytes, with an exception of last byte. A null
+ /// 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
@@ -216,8 +216,7 @@ impl Library {
///
/// # 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.
+ /// 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)?;
@@ -234,12 +233,11 @@ impl Library {
}).map_err(|e| e.unwrap_or(crate::Error::GetProcAddressUnknown))
}
- /// Get a pointer to function or static variable by ordinal number.
+ /// 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. Using a
- /// `Symbol` with a wrong type is undefined.
+ /// Users of this API must specify the correct type of the function or variable loaded.
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 }, || {
@@ -267,8 +265,8 @@ impl Library {
///
/// # Safety
///
- /// The handle shall be a result of a successful call of `LoadLibraryA`, `LoadLibraryW`,
- /// `LoadLibraryExW`, `LoadLibraryExA` or a handle previously returned by the
+ /// 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)
@@ -290,7 +288,7 @@ impl Library {
}).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…
+ // this time it would ignore the return result, which we already seen failing...
std::mem::forget(self);
result
}
@@ -323,17 +321,17 @@ impl fmt::Debug for Library {
}
}
-/// Symbol from a library.
+/// A symbol from a library.
///
-/// A major difference compared to the cross-platform `Symbol` is that this does not ensure the
-/// `Symbol` does not outlive `Library` it comes from.
+/// 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.
+ /// Convert the loaded `Symbol` into a handle.
pub fn into_raw(self) -> FARPROC {
let pointer = self.pointer;
mem::forget(self);
@@ -452,7 +450,7 @@ pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = consts::LOAD_LIBRARY_AS_DA
/// 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 initialization steps.
+/// 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
@@ -462,7 +460,7 @@ pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = consts::LOAD_LIBRARY_AS_DA
/// 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: DWORD = consts::LOAD_LIBRARY_AS_IMAGE_RESOURCE;
-/// Search application's installation directory for the DLL and its dependencies.
+/// 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`].
@@ -509,11 +507,11 @@ pub const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = consts::LOAD_LIBRARY_SEARCH_SYST
/// 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: DWORD = consts::LOAD_LIBRARY_SEARCH_USER_DIRS;
-/// If `filename specifies an absolute path, the system uses the alternate file search strategy
+/// 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 behavior is undefined.
+/// 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
diff --git a/src/safe.rs b/src/safe.rs
new file mode 100644
index 0000000..49be0cf
--- /dev/null
+++ b/src/safe.rs
@@ -0,0 +1,299 @@
+use super::Error;
+#[cfg(libloading_docs)]
+use super::os::unix as imp; // the implementation used here doesn't matter particularly much...
+#[cfg(all(not(libloading_docs), unix))]
+use super::os::unix as imp;
+#[cfg(all(not(libloading_docs), windows))]
+use super::os::windows as imp;
+use std::ffi::OsStr;
+use std::fmt;
+use std::marker;
+use std::ops;
+
+/// A loaded dynamic library.
+#[cfg_attr(libloading_docs, doc(cfg(any(unix, windows))))]
+pub struct Library(imp::Library);
+
+impl Library {
+ /// Find and load a dynamic library.
+ ///
+ /// The `filename` argument may be either:
+ ///
+ /// * A library filename;
+ /// * The absolute path to the library;
+ /// * A relative (to the current working directory) path to the library.
+ ///
+ /// # Safety
+ ///
+ /// When a library is loaded, initialisation routines contained within it 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.
+ ///
+ /// # Thread-safety
+ ///
+ /// 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.
+ ///
+ /// 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
+ ///
+ /// When a plain library filename is supplied, the locations in which the library is searched are
+ /// platform specific and cannot be adjusted in a portable manner. See the documentation for
+ /// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods
+ /// for further information on library lookup behaviour.
+ ///
+ /// If the `filename` specifies a library filename without a path and with the extension omitted,
+ /// the `.dll` extension is implicitly added on Windows.
+ ///
+ /// [`os::unix::Library::new`]: crate::os::unix::Library::new
+ /// [`os::windows::Library::new`]: crate::os::windows::Library::new
+ ///
+ /// # Tips
+ ///
+ /// Distributing your dynamic libraries under a filename common to all platforms (e.g.
+ /// `awesome.module`) allows you to avoid code which has to account for platform’s conventional
+ /// library filenames.
+ ///
+ /// Strive to specify an absolute or at least a relative path to your library, unless
+ /// system-wide libraries are being loaded. Platform-dependent library search locations
+ /// combined with various quirks related to path-less filenames may cause flakiness in
+ /// programs.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use ::libloading::Library;
+ /// // Any of the following are valid.
+ /// unsafe {
+ /// let _ = Library::new("/path/to/awesome.module").unwrap();
+ /// let _ = Library::new("../awesome.module").unwrap();
+ /// let _ = Library::new("libsomelib.so.1").unwrap();
+ /// }
+ /// ```
+ pub unsafe fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, Error> {
+ imp::Library::new(filename).map(From::from)
+ }
+
+ /// 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.
+ ///
+ /// The 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.
+ ///
+ /// # 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.
+ ///
+ /// 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 [`os::unix::Library::get_singlethreaded`] call.
+ ///
+ /// [`os::unix::Library::get_singlethreaded`]: crate::os::unix::Library::get_singlethreaded
+ ///
+ /// # Examples
+ ///
+ /// Given a loaded library:
+ ///
+ /// ```no_run
+ /// # use ::libloading::Library;
+ /// let lib = unsafe {
+ /// Library::new("/path/to/awesome.module").unwrap()
+ /// };
+ /// ```
+ ///
+ /// Loading and using a function looks like this:
+ ///
+ /// ```no_run
+ /// # use ::libloading::{Library, Symbol};
+ /// # let lib = unsafe {
+ /// # Library::new("/path/to/awesome.module").unwrap()
+ /// # };
+ /// unsafe {
+ /// let awesome_function: Symbol<unsafe extern fn(f64) -> f64> =
+ /// lib.get(b"awesome_function\0").unwrap();
+ /// awesome_function(0.42);
+ /// }
+ /// ```
+ ///
+ /// A static variable may also be loaded and inspected:
+ ///
+ /// ```no_run
+ /// # use ::libloading::{Library, Symbol};
+ /// # let lib = unsafe { Library::new("/path/to/awesome.module").unwrap() };
+ /// unsafe {
+ /// let awesome_variable: Symbol<*mut f64> = lib.get(b"awesome_variable\0").unwrap();
+ /// **awesome_variable = 42.0;
+ /// };
+ /// ```
+ pub unsafe fn get<'lib, T>(&'lib self, symbol: &[u8]) -> Result<Symbol<'lib, T>, Error> {
+ self.0.get(symbol).map(|from| Symbol::from_raw(from, self))
+ }
+
+ /// 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<(), Error> {
+ self.0.close()
+ }
+}
+
+impl fmt::Debug for Library {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl From<imp::Library> for Library {
+ fn from(lib: imp::Library) -> Library {
+ Library(lib)
+ }
+}
+
+impl From<Library> for imp::Library {
+ fn from(lib: Library) -> imp::Library {
+ lib.0
+ }
+}
+
+unsafe impl Send for Library {}
+unsafe impl Sync for Library {}
+
+/// Symbol from a library.
+///
+/// This type is a safeguard against using dynamically loaded symbols after a `Library` is
+/// unloaded. The primary method to create an instance of a `Symbol` is via [`Library::get`].
+///
+/// The `Deref` trait implementation allows the use of `Symbol` as if it was a function or variable
+/// itself, without taking care to “extract” the function or variable manually most of the time.
+///
+/// [`Library::get`]: Library::get
+#[cfg_attr(libloading_docs, doc(cfg(any(unix, windows))))]
+pub struct Symbol<'lib, T: 'lib> {
+ inner: imp::Symbol<T>,
+ pd: marker::PhantomData<&'lib T>,
+}
+
+impl<'lib, T> Symbol<'lib, T> {
+ /// Extract the wrapped `os::platform::Symbol`.
+ ///
+ /// # Safety
+ ///
+ /// Using this function relinquishes all the lifetime guarantees. It is up to the developer to
+ /// ensure the resulting `Symbol` is not used past the lifetime of the `Library` this symbol
+ /// was loaded from.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use ::libloading::{Library, Symbol};
+ /// unsafe {
+ /// let lib = Library::new("/path/to/awesome.module").unwrap();
+ /// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
+ /// let symbol = symbol.into_raw();
+ /// }
+ /// ```
+ pub unsafe fn into_raw(self) -> imp::Symbol<T> {
+ self.inner
+ }
+
+ /// 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 a reference to the library.
+ ///
+ /// # Safety
+ ///
+ /// The `library` reference must be exactly the library `sym` was loaded from.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use ::libloading::{Library, Symbol};
+ /// unsafe {
+ /// let lib = Library::new("/path/to/awesome.module").unwrap();
+ /// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
+ /// let symbol = symbol.into_raw();
+ /// let symbol = Symbol::from_raw(symbol, &lib);
+ /// }
+ /// ```
+ 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,
+ }
+ }
+}
+
+impl<'lib, T> Symbol<'lib, Option<T>> {
+ /// Lift Option out of the symbol.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use ::libloading::{Library, Symbol};
+ /// unsafe {
+ /// let lib = Library::new("/path/to/awesome.module").unwrap();
+ /// let symbol: Symbol<Option<*mut u32>> = lib.get(b"symbol\0").unwrap();
+ /// let symbol: Symbol<*mut u32> = symbol.lift_option().expect("static is not null");
+ /// }
+ /// ```
+ pub fn lift_option(self) -> Option<Symbol<'lib, T>> {
+ self.inner.lift_option().map(|is| Symbol {
+ inner: is,
+ pd: marker::PhantomData,
+ })
+ }
+}
+
+impl<'lib, T> Clone for Symbol<'lib, T> {
+ fn clone(&self) -> Symbol<'lib, T> {
+ Symbol {
+ inner: self.inner.clone(),
+ pd: marker::PhantomData,
+ }
+ }
+}
+
+// FIXME: implement FnOnce for callable stuff instead.
+impl<'lib, T> ops::Deref for Symbol<'lib, T> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ ops::Deref::deref(&self.inner)
+ }
+}
+
+impl<'lib, T> fmt::Debug for Symbol<'lib, T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {}
+unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {}
diff --git a/src/util.rs b/src/util.rs
index 880b689..599e6c2 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,10 +1,10 @@
-use std::ffi::{CStr, CString};
use std::borrow::Cow;
+use std::ffi::{CStr, CString};
use std::os::raw;
use crate::Error;
-/// Checks for last byte and avoids allocating if it is zero.
+/// Checks for the last byte and avoids allocating if it is zero.
///
/// Non-last null bytes still result in an error.
pub(crate) fn cstr_cow_from_bytes(slice: &[u8]) -> Result<Cow<'_, CStr>, Error> {
@@ -13,11 +13,14 @@ pub(crate) fn cstr_cow_from_bytes(slice: &[u8]) -> Result<Cow<'_, CStr>, Error>
// Slice out of 0 elements
None => unsafe { Cow::Borrowed(CStr::from_ptr(&ZERO)) },
// Slice with trailing 0
- Some(&0) => Cow::Borrowed(CStr::from_bytes_with_nul(slice)
- .map_err(|source| Error::CreateCStringWithTrailing { source })?),
+ Some(&0) => Cow::Borrowed(
+ CStr::from_bytes_with_nul(slice)
+ .map_err(|source| Error::CreateCStringWithTrailing { source })?,
+ ),
// Slice with no trailing 0
- Some(_) => Cow::Owned(CString::new(slice)
- .map_err(|source| Error::CreateCString { source })?),
+ Some(_) => {
+ Cow::Owned(CString::new(slice).map_err(|source| Error::CreateCString { source })?)
+ }
})
}
diff --git a/tests/constants.rs b/tests/constants.rs
index ad910c4..6ae5a84 100644
--- a/tests/constants.rs
+++ b/tests/constants.rs
@@ -1,5 +1,5 @@
-extern crate libloading;
extern crate libc;
+extern crate libloading;
extern crate static_assertions;
#[cfg(all(test, unix))]
diff --git a/tests/functions.rs b/tests/functions.rs
index eef41e6..795f0cf 100644
--- a/tests/functions.rs
+++ b/tests/functions.rs
@@ -148,7 +148,7 @@ fn test_static_ptr() {
}
#[test]
-// Something about i686-pc-windows-gnu, makes dll initialization code call abort when it is loaded
+// Something about i686-pc-windows-gnu, makes dll initialisation code call abort when it is loaded
// and unloaded many times. So far it seems like an issue with mingw, not libloading, so ignoring
// the target. Especially since it is very unlikely to be fixed given the state of support its
// support.
@@ -193,7 +193,7 @@ fn library_this() {
use libloading::os::windows::Library;
make_helpers();
unsafe {
- // SAFE: well-known library without initializers is loaded.
+ // SAFE: well-known library without initialisers is loaded.
let _lib = Library::new(LIBPATH).unwrap();
let this = Library::this().expect("this library");
// SAFE: functions are never called.