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> {}