libloading/
lib.rs

1//! A memory-safer wrapper around system dynamic library loading primitives.
2//!
3//! Using this library allows loading [dynamic libraries](struct.Library.html) (also known as
4//! shared libraries) as well as use functions and static variables these libraries contain.
5//!
6//! While the library does expose a cross-platform interface to load a library and find stuff
7//! inside it, little is done to paper over the platform differences, especially where library
8//! loading is involved. The documentation for each function will attempt to document such
9//! differences on the best-effort basis.
10//!
11//! Less safe, platform specific bindings are also available. See the
12//! [`os::platform`](os/index.html) module for details.
13//!
14//! # Usage
15//!
16//! Add a dependency on this library to your `Cargo.toml`:
17//!
18//! ```toml
19//! [dependencies]
20//! libloading = "0.5"
21//! ```
22//!
23//! Then inside your project
24//!
25//! ```no_run
26//! extern crate libloading as lib;
27//!
28//! fn call_dynamic() -> Result<u32, Box<dyn std::error::Error>> {
29//!     let lib = lib::Library::new("/path/to/liblibrary.so")?;
30//!     unsafe {
31//!         let func: lib::Symbol<unsafe extern fn() -> u32> = lib.get(b"my_func")?;
32//!         Ok(func())
33//!     }
34//! }
35//! ```
36//!
37//! The compiler will ensure that the loaded `function` will not outlive the `Library` it comes
38//! from, preventing a common cause of undefined behaviour and memory safety problems.
39use std::ffi::OsStr;
40use std::fmt;
41use std::ops;
42use std::marker;
43
44#[cfg(unix)]
45use self::os::unix as imp;
46#[cfg(windows)]
47use self::os::windows as imp;
48pub use self::error::Error;
49
50pub mod os;
51pub mod changelog;
52mod util;
53mod error;
54
55/// A loaded dynamic library.
56pub struct Library(imp::Library);
57
58impl Library {
59    /// Find and load a dynamic library.
60    ///
61    /// The `filename` argument may be any of:
62    ///
63    /// * A library filename;
64    /// * Absolute path to the library;
65    /// * Relative (to the current working directory) path to the library.
66    ///
67    /// ## Thread-safety
68    ///
69    /// The implementation strives to be as MT-safe as sanely possible, however due to certain
70    /// error-handling related resources not always being safe, this library is not MT-safe either.
71    ///
72    /// * On Windows Vista and earlier error handling falls back to [`SetErrorMode`], which is not
73    ///   MT-safe. MT-scenarios involving this function may cause a traditional data race;
74    /// * On some UNIX targets `dlerror` might not be MT-safe, resulting in garbage error messages
75    ///   in certain MT-scenarios.
76    ///
77    /// [`SetErrorMode`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx
78    ///
79    /// Calling this function from multiple threads is not safe if used in conjunction with
80    /// path-less filename and library search path is modified (`SetDllDirectory` function on
81    /// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX).
82    ///
83    /// ## Platform-specific behaviour
84    ///
85    /// When a plain library filename is supplied, locations where library is searched for is
86    /// platform specific and cannot be adjusted in a portable manner.
87    ///
88    /// ### Windows
89    ///
90    /// If the `filename` specifies a library filename without path and with extension omitted,
91    /// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
92    /// trailing `.` to the `filename`.
93    ///
94    /// If the library contains thread local variables (MSVC’s `_declspec(thread)`, Rust’s
95    /// `#[thread_local]` attributes), loading the library will fail on versions prior to Windows
96    /// Vista.
97    ///
98    /// ## Tips
99    ///
100    /// Distributing your dynamic libraries under a filename common to all platforms (e.g.
101    /// `awesome.module`) allows to avoid code which has to account for platform’s conventional
102    /// library filenames.
103    ///
104    /// Strive to specify absolute or relative path to your library, unless system-wide libraries
105    /// are being loaded.  Platform-dependent library search locations combined with various quirks
106    /// related to path-less filenames may cause flaky code.
107    ///
108    /// ## Examples
109    ///
110    /// ```no_run
111    /// # use ::libloading::Library;
112    /// // Any of the following are valid.
113    /// let _ = Library::new("/path/to/awesome.module").unwrap();
114    /// let _ = Library::new("../awesome.module").unwrap();
115    /// let _ = Library::new("libsomelib.so.1").unwrap();
116    /// ```
117    pub fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, Error> {
118        imp::Library::new(filename).map(From::from)
119    }
120
121    /// Get a pointer to function or static variable by symbol name.
122    ///
123    /// The `symbol` may not contain any null bytes, with an exception of last byte. A null
124    /// terminated `symbol` may avoid a string allocation in some cases.
125    ///
126    /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
127    /// most likely invalid.
128    ///
129    /// ## Unsafety
130    ///
131    /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is
132    /// undefined.
133    ///
134    /// ## Platform-specific behaviour
135    ///
136    /// On Linux and Windows, a TLS variable acts just like any regular global variable. OS X uses
137    /// some sort of lazy initialization scheme, which makes loading TLS variables this way
138    /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour.
139    ///
140    /// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such
141    /// as FreeBSD), this function will unconditionally return an error the underlying `dlsym` call
142    /// returns a null pointer. There are rare situations where `dlsym` returns a genuine null
143    /// pointer without it being an error. If loading a null pointer is something you care about,
144    /// consider using the [`os::unix::Library::get_singlethreaded`] call.
145    ///
146    /// ## Examples
147    ///
148    /// Given a loaded library:
149    ///
150    /// ```no_run
151    /// # use ::libloading::Library;
152    /// let lib = Library::new("/path/to/awesome.module").unwrap();
153    /// ```
154    ///
155    /// Loading and using a function looks like this:
156    ///
157    /// ```no_run
158    /// # use ::libloading::{Library, Symbol};
159    /// # let lib = Library::new("/path/to/awesome.module").unwrap();
160    /// unsafe {
161    ///     let awesome_function: Symbol<unsafe extern fn(f64) -> f64> =
162    ///         lib.get(b"awesome_function\0").unwrap();
163    ///     awesome_function(0.42);
164    /// }
165    /// ```
166    ///
167    /// A static variable may also be loaded and inspected:
168    ///
169    /// ```no_run
170    /// # use ::libloading::{Library, Symbol};
171    /// # let lib = Library::new("/path/to/awesome.module").unwrap();
172    /// unsafe {
173    ///     let awesome_variable: Symbol<*mut f64> = lib.get(b"awesome_variable\0").unwrap();
174    ///     **awesome_variable = 42.0;
175    /// };
176    /// ```
177    pub unsafe fn get<'lib, T>(&'lib self, symbol: &[u8]) -> Result<Symbol<'lib, T>, Error> {
178        self.0.get(symbol).map(|from| Symbol::from_raw(from, self))
179    }
180
181    /// Unload the library.
182    ///
183    /// This method might be a no-op, depending on the flags with which the `Library` was opened,
184    /// what library was opened or other platform specifics.
185    ///
186    /// You only need to call this if you are interested in handling any errors that may arise when
187    /// library is unloaded. Otherwise the implementation of `Drop` for `Library` will close the
188    /// library and ignore the errors were they arise.
189    pub fn close(self) -> Result<(), Error> {
190        self.0.close()
191    }
192}
193
194impl fmt::Debug for Library {
195    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196        self.0.fmt(f)
197    }
198}
199
200impl From<imp::Library> for Library {
201    fn from(lib: imp::Library) -> Library {
202        Library(lib)
203    }
204}
205
206impl From<Library> for imp::Library {
207    fn from(lib: Library) -> imp::Library {
208        lib.0
209    }
210}
211
212unsafe impl Send for Library {}
213unsafe impl Sync for Library {}
214
215/// Symbol from a library.
216///
217/// This type is a safeguard against using dynamically loaded symbols after a `Library` is
218/// unloaded. Primary method to create an instance of a `Symbol` is via `Library::get`.
219///
220/// Due to implementation of the `Deref` trait, an instance of `Symbol` may be used as if it was a
221/// function or variable directly, without taking care to “extract” function or variable manually
222/// most of the time.
223///
224/// See [`Library::get`] for details.
225///
226/// [`Library::get`]: ./struct.Library.html#method.get
227pub struct Symbol<'lib, T: 'lib> {
228    inner: imp::Symbol<T>,
229    pd: marker::PhantomData<&'lib T>
230}
231
232impl<'lib, T> Symbol<'lib, T> {
233    /// Extract the wrapped `os::platform::Symbol`.
234    ///
235    /// ## Unsafety
236    /// Using this function relinquishes all the lifetime guarantees. It is up to programmer to
237    /// ensure the resulting `Symbol` is not used past the lifetime of the `Library` this symbol
238    /// was loaded from.
239    ///
240    /// ## Examples
241    ///
242    /// ```no_run
243    /// # use ::libloading::{Library, Symbol};
244    /// let lib = Library::new("/path/to/awesome.module").unwrap();
245    /// unsafe {
246    ///     let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
247    ///     let symbol = symbol.into_raw();
248    /// }
249    /// ```
250    pub unsafe fn into_raw(self) -> imp::Symbol<T> {
251        self.inner
252    }
253
254    /// Wrap the `os::platform::Symbol` into this safe wrapper.
255    ///
256    /// Note that, in order to create association between the symbol and the library this symbol
257    /// came from, this function requires reference to the library provided.
258    ///
259    /// ## Unsafety
260    ///
261    /// It is invalid to provide a reference to any other value other than the library the `sym`
262    /// was loaded from. Doing so invalidates any lifetime guarantees.
263    ///
264    /// ## Examples
265    ///
266    /// ```no_run
267    /// # use ::libloading::{Library, Symbol};
268    /// let lib = Library::new("/path/to/awesome.module").unwrap();
269    /// unsafe {
270    ///     let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
271    ///     let symbol = symbol.into_raw();
272    ///     let symbol = Symbol::from_raw(symbol, &lib);
273    /// }
274    /// ```
275    pub unsafe fn from_raw<L>(sym: imp::Symbol<T>, _: &'lib L) -> Symbol<'lib, T> {
276        Symbol {
277            inner: sym,
278            pd: marker::PhantomData
279        }
280    }
281}
282
283impl<'lib, T> Symbol<'lib, Option<T>> {
284    /// Lift Option out of the symbol.
285    ///
286    /// ## Examples
287    ///
288    /// ```no_run
289    /// # use ::libloading::{Library, Symbol};
290    /// let lib = Library::new("/path/to/awesome.module").unwrap();
291    /// unsafe {
292    ///     let symbol: Symbol<Option<*mut u32>> = lib.get(b"symbol\0").unwrap();
293    ///     let symbol: Symbol<*mut u32> = symbol.lift_option().expect("static is not null");
294    /// }
295    /// ```
296    pub fn lift_option(self) -> Option<Symbol<'lib, T>> {
297        self.inner.lift_option().map(|is| Symbol {
298            inner: is,
299            pd: marker::PhantomData,
300        })
301    }
302}
303
304impl<'lib, T> Clone for Symbol<'lib, T> {
305    fn clone(&self) -> Symbol<'lib, T> {
306        Symbol {
307            inner: self.inner.clone(),
308            pd: marker::PhantomData
309        }
310    }
311}
312
313// FIXME: implement FnOnce for callable stuff instead.
314impl<'lib, T> ops::Deref for Symbol<'lib, T> {
315    type Target = T;
316    fn deref(&self) -> &T {
317        ops::Deref::deref(&self.inner)
318    }
319}
320
321impl<'lib, T> fmt::Debug for Symbol<'lib, T> {
322    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
323        self.inner.fmt(f)
324    }
325}
326
327unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {}
328unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {}