summaryrefslogtreecommitdiffstats
path: root/third_party/rust/libloading/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/rust/libloading/src
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/libloading/src')
-rw-r--r--third_party/rust/libloading/src/changelog.rs332
-rw-r--r--third_party/rust/libloading/src/error.rs130
-rw-r--r--third_party/rust/libloading/src/lib.rs80
-rw-r--r--third_party/rust/libloading/src/os/mod.rs27
-rw-r--r--third_party/rust/libloading/src/os/unix/consts.rs237
-rw-r--r--third_party/rust/libloading/src/os/unix/mod.rs444
-rw-r--r--third_party/rust/libloading/src/os/windows/mod.rs532
-rw-r--r--third_party/rust/libloading/src/safe.rs299
-rw-r--r--third_party/rust/libloading/src/test_helpers.rs37
-rw-r--r--third_party/rust/libloading/src/util.rs34
10 files changed, 2152 insertions, 0 deletions
diff --git a/third_party/rust/libloading/src/changelog.rs b/third_party/rust/libloading/src/changelog.rs
new file mode 100644
index 0000000000..162544f34f
--- /dev/null
+++ b/third_party/rust/libloading/src/changelog.rs
@@ -0,0 +1,332 @@
+//! The change log.
+
+/// Release 0.7.4 (2022-11-07)
+///
+/// This release has no functional changes.
+///
+/// `RTLD_LAZY`, `RTLD_GLOBAL` and `RTLD_LOCAL` constants have been implemented for AIX platforms.
+pub mod r0_7_4 {}
+
+/// 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
+///
+/// ### Loading functions are now `unsafe`
+///
+/// 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 (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 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
+///
+/// The (broken) support for Windows XP and Windows Vista environments was removed. This was
+/// prompted primarily by a similar policy change in the [Rust
+/// 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
+/// [`Error::LoadLibraryExW`]: crate::Error::LoadLibraryExW
+/// [`os::unix::Library::this`]: crate::os::unix::Library::this
+/// [`os::unix::Library::new`]: crate::os::unix::Library::new
+/// [`os::unix::Library::open`]: crate::os::unix::Library::new
+/// [`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_GLOBAL`]: crate::os::unix::RTLD_GLOBAL
+pub mod r0_7_0 {}
+
+/// Release 0.6.7 (2021-01-14)
+///
+/// * Added a [`os::windows::Library::open_already_loaded`] to obtain a handle to a library that
+/// must already be loaded. There is no portable equivalent for all UNIX targets. Users who do not
+/// care about portability across UNIX platforms may use [`os::unix::Library::open`] with
+/// `libc::RTLD_NOLOAD`;
+///
+/// [`os::windows::Library::open_already_loaded`]: crate::os::windows::Library::open_already_loaded
+/// [`os::unix::Library::open`]: crate::os::unix::Library::open
+pub mod r0_6_7 {}
+
+/// Release 0.6.6 (2020-12-03)
+///
+/// * Fix a double-release of resources when [`Library::close`] or [`os::windows::Library::close`]
+/// is used on Windows.
+///
+/// [`Library::close`]: crate::Library::close
+/// [`os::windows::Library::close`]: crate::os::windows::Library::close
+pub mod r0_6_6 {}
+
+/// Release 0.6.5 (2020-10-23)
+///
+/// * Upgrade cfg-if 0.1 to 1.0
+pub mod r0_6_5 {}
+
+/// Release 0.6.4 (2020-10-10)
+///
+/// * Remove use of `build.rs` making it easier to build `libloading` without cargo. It also
+/// almost halves the build time of this crate.
+pub mod r0_6_4 {}
+
+/// Release 0.6.3 (2020-08-22)
+///
+/// * Improve documentation, allowing to view all of the os-specific functionality from
+/// documentation generated for any target;
+/// * Add [`os::windows::Library::this`];
+/// * Added constants to use with OS-specific `Library::open`;
+/// * Add [`library_filename`].
+///
+/// [`os::windows::Library::this`]: crate::os::windows::Library::this
+/// [`library_filename`]: crate::library_filename
+pub mod r0_6_3 {}
+
+/// Release 0.6.2 (2020-05-06)
+///
+/// * Fixed building of this library on Illumos.
+pub mod r0_6_2 {}
+
+/// Release 0.6.1 (2020-04-15)
+///
+/// * Introduced a new method [`os::windows::Library::load_with_flags`];
+/// * Added support for the Illumos triple.
+///
+/// [`os::windows::Library::load_with_flags`]: crate::os::windows::Library::load_with_flags
+pub mod r0_6_1 {}
+
+/// Release 0.6.0 (2020-04-05)
+///
+/// * Introduced a new method [`os::unix::Library::get_singlethreaded`];
+/// * Added (untested) support for building when targeting Redox and Fuchsia;
+/// * The APIs exposed by this library no longer panic and instead return an `Err` when it used
+/// to panic.
+///
+/// ## Breaking changes
+///
+/// * Minimum required (stable) version of Rust to build this library is now 1.40.0;
+/// * This crate now implements a custom [`Error`] type and all APIs now return this type rather
+/// than returning the `std::io::Error`;
+/// * `libloading::Result` has been removed;
+/// * Removed the dependency on the C compiler to build this library on UNIX-like platforms.
+/// `libloading` used to utilize a snippet written in C to work-around the unlikely possibility
+/// of the target having a thread-unsafe implementation of the `dlerror` function. The effect of
+/// the work-around was very opportunistic: it would not work if the function was called by
+/// forgoing `libloading`.
+///
+/// Starting with 0.6.0, [`Library::get`] on platforms where `dlerror` is not MT-safe (such as
+/// FreeBSD, DragonflyBSD or NetBSD) will unconditionally return an error when the underlying
+/// `dlsym` returns a null pointer. For the use-cases where loading null pointers is necessary
+/// consider using [`os::unix::Library::get_singlethreaded`] instead.
+///
+/// [`Library::get`]: crate::Library::get
+/// [`os::unix::Library::get_singlethreaded`]: crate::os::unix::Library::get_singlethreaded
+/// [`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.
+pub mod r0_5_2 {}
+
+/// Release 0.5.1 (2019-06-01)
+///
+/// * Build on Haiku targets.
+pub mod r0_5_1 {}
+
+/// Release 0.5.0 (2018-01-11)
+///
+/// * Update to `winapi = ^0.3`;
+///
+/// ## Breaking changes
+///
+/// * libloading now requires a C compiler to build on UNIX;
+/// * This is a temporary measure until the [`linkage`] attribute is stabilised;
+/// * Necessary to resolve [#32].
+///
+/// [`linkage`]: https://github.com/rust-lang/rust/issues/29603
+/// [#32]: https://github.com/nagisa/rust_libloading/issues/32
+pub mod r0_5_0 {}
+
+/// Release 0.4.3 (2017-12-07)
+///
+/// * Bump lazy-static dependency to `^1.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;
+/// * Improved documentation about thread-safety of Library;
+/// * 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
+pub mod r0_4_1 {}
+
+/// Release 0.4.0 (2017-05-01)
+///
+/// * Remove build-time dependency on target_build_utils (and by extension serde/phf);
+/// * Require at least version 1.14.0 of rustc to build;
+/// * Actually, it is cargo which has to be more recent here. The one shipped with rustc 1.14.0
+/// is what’s being required from now on.
+pub mod r0_4_0 {}
+
+/// Release 0.3.4 (2017-03-25)
+///
+/// * Remove rogue println!
+pub mod r0_3_4 {}
+
+/// Release 0.3.3 (2017-03-25)
+///
+/// * Panics when `Library::get` is called for incompatibly sized type such as named function
+/// types (which are zero-sized).
+pub mod r0_3_3 {}
+
+/// Release 0.3.2 (2017-02-10)
+///
+/// * Minimum version required is now rustc 1.12.0;
+/// * Updated dependency versions (most notably target_build_utils to 0.3.0)
+pub mod r0_3_2 {}
+
+/// Release 0.3.1 (2016-10-01)
+///
+/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Send` where `T: Send`;
+/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Sync` where `T: Sync`;
+/// * `Library` and `os::*::Library` now implement `Sync` (they were `Send` in 0.3.0 already).
+pub mod r0_3_1 {}
+
+/// Release 0.3.0 (2016-07-27)
+///
+/// * Greatly improved documentation, especially around platform-specific behaviours;
+/// * Improved test suite by building our own library to test against;
+/// * All `Library`-ies now implement `Send`.
+/// * Added `impl From<os::platform::Library> for Library` and `impl From<Library> for
+/// os::platform::Library` allowing wrapping and extracting the platform-specific library handle;
+/// * Added methods to wrap (`Symbol::from_raw`) and unwrap (`Symbol::into_raw`) the safe `Symbol`
+/// wrapper into unsafe `os::platform::Symbol`.
+///
+/// The last two additions focus on not restricting potential usecases of this library, allowing
+/// users of the library to circumvent safety checks if need be.
+///
+/// ## Breaking Changes
+///
+/// `Library::new` defaults to `RTLD_NOW` instead of `RTLD_LAZY` on UNIX for more consistent
+/// cross-platform behaviour. If a library loaded with `Library::new` had any linking errors, but
+/// unresolved references weren’t forced to be resolved, the library would’ve “just worked”,
+/// whereas now the call to `Library::new` will return an error signifying presence of such error.
+///
+/// ## os::platform
+/// * Added `os::unix::Library::open` which allows specifying arbitrary flags (e.g. `RTLD_LAZY`);
+/// * Added `os::windows::Library::get_ordinal` which allows finding a function or variable by its
+/// ordinal number;
+pub mod r0_3_0 {}
diff --git a/third_party/rust/libloading/src/error.rs b/third_party/rust/libloading/src/error.rs
new file mode 100644
index 0000000000..bd70ec39ce
--- /dev/null
+++ b/third_party/rust/libloading/src/error.rs
@@ -0,0 +1,130 @@
+use std::ffi::CString;
+
+/// A `dlerror` error.
+pub struct DlDescription(pub(crate) CString);
+
+impl std::fmt::Debug for DlDescription {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ std::fmt::Debug::fmt(&self.0, f)
+ }
+}
+
+/// A Windows API error.
+pub struct WindowsError(pub(crate) std::io::Error);
+
+impl std::fmt::Debug for WindowsError {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ std::fmt::Debug::fmt(&self.0, f)
+ }
+}
+
+/// Errors.
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum Error {
+ /// The `dlopen` call failed.
+ DlOpen {
+ /// The source error.
+ desc: DlDescription
+ },
+ /// The `dlopen` call failed and system did not report an error.
+ DlOpenUnknown,
+ /// The `dlsym` call failed.
+ DlSym {
+ /// The source error.
+ desc: DlDescription
+ },
+ /// The `dlsym` call failed and system did not report an error.
+ DlSymUnknown,
+ /// The `dlclose` call failed.
+ DlClose {
+ /// The source error.
+ desc: DlDescription
+ },
+ /// The `dlclose` call failed and system did not report an error.
+ DlCloseUnknown,
+ /// The `LoadLibraryW` call failed.
+ LoadLibraryExW {
+ /// The source error.
+ source: WindowsError
+ },
+ /// The `LoadLibraryW` call failed and system did not report an error.
+ LoadLibraryExWUnknown,
+ /// The `GetModuleHandleExW` call failed.
+ GetModuleHandleExW {
+ /// The source error.
+ source: WindowsError
+ },
+ /// The `GetModuleHandleExW` call failed and system did not report an error.
+ GetModuleHandleExWUnknown,
+ /// The `GetProcAddress` call failed.
+ GetProcAddress {
+ /// The source error.
+ source: WindowsError
+ },
+ /// The `GetProcAddressUnknown` call failed and system did not report an error.
+ GetProcAddressUnknown,
+ /// The `FreeLibrary` call failed.
+ FreeLibrary {
+ /// The source error.
+ source: WindowsError
+ },
+ /// The `FreeLibrary` call failed and system did not report an error.
+ FreeLibraryUnknown,
+ /// The requested type cannot possibly work.
+ IncompatibleSize,
+ /// Could not create a new CString.
+ CreateCString {
+ /// The source error.
+ source: std::ffi::NulError
+ },
+ /// Could not create a new CString from bytes with trailing null.
+ CreateCStringWithTrailing {
+ /// The source error.
+ source: std::ffi::FromBytesWithNulError
+ },
+}
+
+impl std::error::Error for Error {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ use Error::*;
+ match *self {
+ CreateCString { ref source } => Some(source),
+ CreateCStringWithTrailing { ref source } => Some(source),
+ LoadLibraryExW { ref source } => Some(&source.0),
+ GetProcAddress { ref source } => Some(&source.0),
+ FreeLibrary { ref source } => Some(&source.0),
+ _ => None,
+ }
+ }
+}
+
+impl std::fmt::Display for Error {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ use Error::*;
+ match *self {
+ DlOpen { ref desc } => write!(f, "{}", desc.0.to_string_lossy()),
+ DlOpenUnknown => write!(f, "dlopen failed, but system did not report the error"),
+ DlSym { ref desc } => write!(f, "{}", desc.0.to_string_lossy()),
+ DlSymUnknown => write!(f, "dlsym failed, but system did not report the error"),
+ DlClose { ref desc } => write!(f, "{}", desc.0.to_string_lossy()),
+ DlCloseUnknown => write!(f, "dlclose failed, but system did not report the error"),
+ LoadLibraryExW { .. } => write!(f, "LoadLibraryExW failed"),
+ LoadLibraryExWUnknown =>
+ write!(f, "LoadLibraryExW failed, but system did not report the error"),
+ GetModuleHandleExW { .. } => write!(f, "GetModuleHandleExW failed"),
+ GetModuleHandleExWUnknown =>
+ write!(f, "GetModuleHandleExWUnknown failed, but system did not report the error"),
+ GetProcAddress { .. } => write!(f, "GetProcAddress failed"),
+ GetProcAddressUnknown =>
+ write!(f, "GetProcAddress failed, but system did not report the error"),
+ FreeLibrary { .. } => write!(f, "FreeLibrary failed"),
+ FreeLibraryUnknown =>
+ write!(f, "FreeLibrary failed, but system did not report the error"),
+ CreateCString { .. } => write!(f, "could not create a C string from bytes"),
+ CreateCStringWithTrailing { .. } =>
+ write!(f, "could not create a C string from bytes with trailing null"),
+ IncompatibleSize => write!(f, "requested type cannot possibly work"),
+ }
+ }
+}
diff --git a/third_party/rust/libloading/src/lib.rs b/third_party/rust/libloading/src/lib.rs
new file mode 100644
index 0000000000..6f0e4cb7f7
--- /dev/null
+++ b/third_party/rust/libloading/src/lib.rs
@@ -0,0 +1,80 @@
+//! Bindings around the platform's dynamic library loading primitives with greatly improved memory safety.
+//!
+//! 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.
+//!
+//! 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.
+//!
+//! # Installation
+//!
+//! Add the `libloading` library to your dependencies in `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! libloading = "0.7"
+//! ```
+//!
+//! # Usage
+//!
+//! In your code, run the following:
+//!
+//! ```no_run
+//! fn call_dynamic() -> Result<u32, Box<dyn std::error::Error>> {
+//! unsafe {
+//! 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` 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))]
+
+pub mod changelog;
+pub mod os;
+mod util;
+
+mod error;
+pub use self::error::Error;
+
+#[cfg(any(unix, windows, libloading_docs))]
+mod safe;
+#[cfg(any(unix, windows, libloading_docs))]
+pub use self::safe::{Library, Symbol};
+
+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.
+///
+/// This function will prepend prefixes (such as `lib`) and suffixes (such as `.so`) to the library
+/// `name` to construct the filename.
+///
+/// # Examples
+///
+/// It can be used to load global libraries in a platform independent manner:
+///
+/// ```
+/// use libloading::{Library, library_filename};
+/// // Will attempt to load `libLLVM.so` on Linux, `libLLVM.dylib` on macOS and `LLVM.dll` on
+/// // Windows.
+/// let library = unsafe {
+/// Library::new(library_filename("LLVM"))
+/// };
+/// ```
+pub fn library_filename<S: AsRef<OsStr>>(name: S) -> OsString {
+ let name = name.as_ref();
+ let mut string = OsString::with_capacity(name.len() + DLL_PREFIX.len() + DLL_SUFFIX.len());
+ string.push(DLL_PREFIX);
+ string.push(name);
+ string.push(DLL_SUFFIX);
+ string
+}
diff --git a/third_party/rust/libloading/src/os/mod.rs b/third_party/rust/libloading/src/os/mod.rs
new file mode 100644
index 0000000000..710353f5ef
--- /dev/null
+++ b/third_party/rust/libloading/src/os/mod.rs
@@ -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;
diff --git a/third_party/rust/libloading/src/os/unix/consts.rs b/third_party/rust/libloading/src/os/unix/consts.rs
new file mode 100644
index 0000000000..ea7a6a102d
--- /dev/null
+++ b/third_party/rust/libloading/src/os/unix/consts.rs
@@ -0,0 +1,237 @@
+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",
+ ))] {
+ 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",
+ ))] {
+ 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",
+ ))] {
+ 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(target_os = "netbsd")] {
+ 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",
+ ))] {
+ 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
diff --git a/third_party/rust/libloading/src/os/unix/mod.rs b/third_party/rust/libloading/src/os/unix/mod.rs
new file mode 100644
index 0000000000..df7efdad54
--- /dev/null
+++ b/third_party/rust/libloading/src/os/unix/mod.rs
@@ -0,0 +1,444 @@
+// 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;
+
+// dl* family of functions did not have enough thought put into it.
+//
+// Whole error handling scheme is done via setting and querying some global state, therefore 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 MT-safe.
+//
+// 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. Regardless the comments in this function shall
+// remain as a documentation for the future generations.
+fn with_dlerror<T, F>(wrap: fn(crate::error::DlDescription) -> crate::Error, closure: F)
+-> Result<T, Option<crate::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 error = dlerror();
+ if error.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.
+ let message = CStr::from_ptr(error).into();
+ Some(wrap(crate::error::DlDescription(message)))
+ // 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(|desc| crate::Error::DlOpen { desc }, 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
+ })
+ }
+ }).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.
+ match with_dlerror(|desc| crate::Error::DlSym { desc }, || {
+ dlerror();
+ let symbol = dlsym(self.handle, symbol.as_ptr());
+ if symbol.is_null() {
+ None
+ } else {
+ Some(Symbol {
+ pointer: symbol,
+ pd: marker::PhantomData
+ })
+ }
+ }) {
+ 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(|desc| crate::Error::DlClose { desc }, || {
+ if unsafe { dlclose(self.handle) } == 0 {
+ Some(())
+ } else {
+ None
+ }
+ }).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 {
+ 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
+}
diff --git a/third_party/rust/libloading/src/os/windows/mod.rs b/third_party/rust/libloading/src/os/windows/mod.rs
new file mode 100644
index 0000000000..e3da940a29
--- /dev/null
+++ b/third_party/rust/libloading/src/os/windows/mod.rs
@@ -0,0 +1,532 @@
+// 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 {
+ pub(super) enum WORD {}
+ pub(super) struct DWORD;
+ pub(super) enum HMODULE {}
+ pub(super) enum FARPROC {}
+
+ pub(super) mod consts {
+ use super::DWORD;
+ pub(crate) const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = DWORD;
+ pub(crate) const LOAD_LIBRARY_AS_DATAFILE: DWORD = DWORD;
+ pub(crate) const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = DWORD;
+ pub(crate) const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = DWORD;
+ pub(crate) const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = DWORD;
+ pub(crate) const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = DWORD;
+ pub(crate) const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = DWORD;
+ pub(crate) const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = DWORD;
+ pub(crate) const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = DWORD;
+ pub(crate) const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = DWORD;
+ pub(crate) const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = DWORD;
+ pub(crate) const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = DWORD;
+ }
+}
+#[cfg(any(not(libloading_docs), windows))]
+mod windows_imports {
+ extern crate winapi;
+ pub(super) use self::winapi::shared::minwindef::{WORD, DWORD, HMODULE, FARPROC};
+ pub(super) use self::winapi::shared::ntdef::WCHAR;
+ pub(super) use self::winapi::um::{errhandlingapi, libloaderapi};
+ pub(super) use std::os::windows::ffi::{OsStrExt, OsStringExt};
+ pub(super) const SEM_FAILCE: DWORD = 1;
+
+ pub(super) mod consts {
+ pub(crate) use super::winapi::um::libloaderapi::{
+ LOAD_IGNORE_CODE_AUTHZ_LEVEL,
+ LOAD_LIBRARY_AS_DATAFILE,
+ LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE,
+ LOAD_LIBRARY_AS_IMAGE_RESOURCE,
+ LOAD_LIBRARY_SEARCH_APPLICATION_DIR,
+ LOAD_LIBRARY_SEARCH_DEFAULT_DIRS,
+ LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR,
+ LOAD_LIBRARY_SEARCH_SYSTEM32,
+ LOAD_LIBRARY_SEARCH_USER_DIRS,
+ LOAD_WITH_ALTERED_SEARCH_PATH,
+ LOAD_LIBRARY_REQUIRE_SIGNED_TARGET,
+ LOAD_LIBRARY_SAFE_CURRENT_DIRS,
+ };
+ }
+}
+
+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 = std::ptr::null_mut();
+ with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || {
+ let result = libloaderapi::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 = std::ptr::null_mut();
+ 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 = libloaderapi::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: DWORD) -> 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 =
+ libloaderapi::LoadLibraryExW(wide_filename.as_ptr(), std::ptr::null_mut(), flags);
+ if handle.is_null() {
+ 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 = libloaderapi::GetProcAddress(self.0, symbol.as_ptr());
+ if symbol.is_null() {
+ 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: WORD) -> 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 *mut _;
+ let symbol = libloaderapi::GetProcAddress(self.0, ordinal);
+ if symbol.is_null() {
+ 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 { libloaderapi::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 { libloaderapi::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::<WCHAR>; 1024]>::uninit().assume_init();
+ let len = libloaderapi::GetModuleFileNameW(self.0,
+ buf[..].as_mut_ptr().cast(), 1024) as usize;
+ if len == 0 {
+ f.write_str(&format!("Library@{:p}", self.0))
+ } else {
+ let string: OsString = OsString::from_wide(
+ // FIXME: use Maybeuninit::slice_get_ref when stable
+ &*(&buf[..len] as *const [_] as *const [WCHAR])
+ );
+ f.write_str(&format!("Library@{:p} 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_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 {
+ f.write_str(&format!("Symbol@{:p}", self.pointer))
+ }
+}
+
+struct ErrorModeGuard(DWORD);
+
+impl ErrorModeGuard {
+ #[allow(clippy::if_same_then_else)]
+ fn new() -> Option<ErrorModeGuard> {
+ unsafe {
+ let mut previous_mode = 0;
+ if errhandlingapi::SetThreadErrorMode(SEM_FAILCE, &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_FAILCE {
+ None
+ } else {
+ Some(ErrorModeGuard(previous_mode))
+ }
+ }
+ }
+}
+
+impl Drop for ErrorModeGuard {
+ fn drop(&mut self) {
+ unsafe {
+ errhandlingapi::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 { errhandlingapi::GetLastError() };
+ if error == 0 {
+ None
+ } else {
+ Some(wrap(crate::error::WindowsError(io::Error::from_raw_os_error(error as i32))))
+ }
+ })
+}
+
+/// 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: DWORD = consts::LOAD_IGNORE_CODE_AUTHZ_LEVEL;
+
+/// 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: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE;
+
+/// 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: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE;
+
+/// 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: DWORD = consts::LOAD_LIBRARY_AS_IMAGE_RESOURCE;
+
+/// 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: DWORD = consts::LOAD_LIBRARY_SEARCH_APPLICATION_DIR;
+
+/// 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: DWORD = consts::LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;
+
+/// 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: DWORD = consts::LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
+
+/// 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: DWORD = consts::LOAD_LIBRARY_SEARCH_SYSTEM32;
+
+/// 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: DWORD = consts::LOAD_LIBRARY_SEARCH_USER_DIRS;
+
+/// 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: DWORD = consts::LOAD_WITH_ALTERED_SEARCH_PATH;
+
+/// 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: DWORD = consts::LOAD_LIBRARY_REQUIRE_SIGNED_TARGET;
+
+/// 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: DWORD = consts::LOAD_LIBRARY_SAFE_CURRENT_DIRS;
diff --git a/third_party/rust/libloading/src/safe.rs b/third_party/rust/libloading/src/safe.rs
new file mode 100644
index 0000000000..49be0cfc9a
--- /dev/null
+++ b/third_party/rust/libloading/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/third_party/rust/libloading/src/test_helpers.rs b/third_party/rust/libloading/src/test_helpers.rs
new file mode 100644
index 0000000000..9e3e9924ff
--- /dev/null
+++ b/third_party/rust/libloading/src/test_helpers.rs
@@ -0,0 +1,37 @@
+//! This is a separate file containing helpers for tests of this library. It is built into a
+//! dynamic library by the build.rs script.
+#![crate_type="cdylib"]
+
+#[no_mangle]
+pub static mut TEST_STATIC_U32: u32 = 0;
+
+#[no_mangle]
+pub static mut TEST_STATIC_PTR: *mut () = 0 as *mut _;
+
+#[no_mangle]
+pub extern "C" fn test_identity_u32(x: u32) -> u32 {
+ x
+}
+
+#[repr(C)]
+pub struct S {
+ a: u64,
+ b: u32,
+ c: u16,
+ d: u8
+}
+
+#[no_mangle]
+pub extern "C" fn test_identity_struct(x: S) -> S {
+ x
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn test_get_static_u32() -> u32 {
+ TEST_STATIC_U32
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn test_check_static_ptr() -> bool {
+ TEST_STATIC_PTR == (&mut TEST_STATIC_PTR as *mut *mut _ as *mut _)
+}
diff --git a/third_party/rust/libloading/src/util.rs b/third_party/rust/libloading/src/util.rs
new file mode 100644
index 0000000000..599e6c254e
--- /dev/null
+++ b/third_party/rust/libloading/src/util.rs
@@ -0,0 +1,34 @@
+use std::borrow::Cow;
+use std::ffi::{CStr, CString};
+use std::os::raw;
+
+use crate::Error;
+
+/// 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> {
+ static ZERO: raw::c_char = 0;
+ Ok(match slice.last() {
+ // 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 })?,
+ ),
+ // Slice with no trailing 0
+ Some(_) => {
+ Cow::Owned(CString::new(slice).map_err(|source| Error::CreateCString { source })?)
+ }
+ })
+}
+
+#[inline]
+pub(crate) fn ensure_compatible_types<T, E>() -> Result<(), Error> {
+ if ::std::mem::size_of::<T>() != ::std::mem::size_of::<E>() {
+ Err(Error::IncompatibleSize)
+ } else {
+ Ok(())
+ }
+}