• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::Error;
2 #[cfg(libloading_docs)]
3 use super::os::unix as imp; // the implementation used here doesn't matter particularly much...
4 #[cfg(all(not(libloading_docs), unix))]
5 use super::os::unix as imp;
6 #[cfg(all(not(libloading_docs), windows))]
7 use super::os::windows as imp;
8 use std::ffi::OsStr;
9 use std::fmt;
10 use std::marker;
11 use std::ops;
12 
13 /// A loaded dynamic library.
14 #[cfg_attr(libloading_docs, doc(cfg(any(unix, windows))))]
15 pub struct Library(imp::Library);
16 
17 impl Library {
18     /// Find and load a dynamic library.
19     ///
20     /// The `filename` argument may be either:
21     ///
22     /// * A library filename;
23     /// * The absolute path to the library;
24     /// * A relative (to the current working directory) path to the library.
25     ///
26     /// # Safety
27     ///
28     /// When a library is loaded, initialisation routines contained within it are executed.
29     /// For the purposes of safety, the execution of these routines is conceptually the same calling an
30     /// unknown foreign function and may impose arbitrary requirements on the caller for the call
31     /// to be sound.
32     ///
33     /// Additionally, the callers of this function must also ensure that execution of the
34     /// termination routines contained within the library is safe as well. These routines may be
35     /// executed when the library is unloaded.
36     ///
37     /// # Thread-safety
38     ///
39     /// The implementation strives to be as MT-safe as sanely possible, however on certain
40     /// platforms the underlying error-handling related APIs not always MT-safe. This library
41     /// shares these limitations on those platforms. In particular, on certain UNIX targets
42     /// `dlerror` is not MT-safe, resulting in garbage error messages in certain MT-scenarios.
43     ///
44     /// Calling this function from multiple threads is not MT-safe if used in conjunction with
45     /// library filenames and the library search path is modified (`SetDllDirectory` function on
46     /// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX).
47     ///
48     /// # Platform-specific behaviour
49     ///
50     /// When a plain library filename is supplied, the locations in which the library is searched are
51     /// platform specific and cannot be adjusted in a portable manner. See the documentation for
52     /// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods
53     /// for further information on library lookup behaviour.
54     ///
55     /// If the `filename` specifies a library filename without a path and with the extension omitted,
56     /// the `.dll` extension is implicitly added on Windows.
57     ///
58     /// [`os::unix::Library::new`]: crate::os::unix::Library::new
59     /// [`os::windows::Library::new`]: crate::os::windows::Library::new
60     ///
61     /// # Tips
62     ///
63     /// Distributing your dynamic libraries under a filename common to all platforms (e.g.
64     /// `awesome.module`) allows you to avoid code which has to account for platform’s conventional
65     /// library filenames.
66     ///
67     /// Strive to specify an absolute or at least a relative path to your library, unless
68     /// system-wide libraries are being loaded. Platform-dependent library search locations
69     /// combined with various quirks related to path-less filenames may cause flakiness in
70     /// programs.
71     ///
72     /// # Examples
73     ///
74     /// ```no_run
75     /// # use ::libloading::Library;
76     /// // Any of the following are valid.
77     /// unsafe {
78     ///     let _ = Library::new("/path/to/awesome.module").unwrap();
79     ///     let _ = Library::new("../awesome.module").unwrap();
80     ///     let _ = Library::new("libsomelib.so.1").unwrap();
81     /// }
82     /// ```
new<P: AsRef<OsStr>>(filename: P) -> Result<Library, Error>83     pub unsafe fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, Error> {
84         imp::Library::new(filename).map(From::from)
85     }
86 
87     /// Get a pointer to a function or static variable by symbol name.
88     ///
89     /// The `symbol` may not contain any null bytes, with the exception of the last byte. Providing a
90     /// null-terminated `symbol` may help to avoid an allocation.
91     ///
92     /// The symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
93     /// most likely invalid.
94     ///
95     /// # Safety
96     ///
97     /// Users of this API must specify the correct type of the function or variable loaded.
98     ///
99     /// # Platform-specific behaviour
100     ///
101     /// The implementation of thread-local variables is extremely platform specific and uses of such
102     /// variables that work on e.g. Linux may have unintended behaviour on other targets.
103     ///
104     /// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such
105     /// as FreeBSD), this function will unconditionally return an error when the underlying `dlsym`
106     /// call returns a null pointer. There are rare situations where `dlsym` returns a genuine null
107     /// pointer without it being an error. If loading a null pointer is something you care about,
108     /// consider using the [`os::unix::Library::get_singlethreaded`] call.
109     ///
110     /// [`os::unix::Library::get_singlethreaded`]: crate::os::unix::Library::get_singlethreaded
111     ///
112     /// # Examples
113     ///
114     /// Given a loaded library:
115     ///
116     /// ```no_run
117     /// # use ::libloading::Library;
118     /// let lib = unsafe {
119     ///     Library::new("/path/to/awesome.module").unwrap()
120     /// };
121     /// ```
122     ///
123     /// Loading and using a function looks like this:
124     ///
125     /// ```no_run
126     /// # use ::libloading::{Library, Symbol};
127     /// # let lib = unsafe {
128     /// #     Library::new("/path/to/awesome.module").unwrap()
129     /// # };
130     /// unsafe {
131     ///     let awesome_function: Symbol<unsafe extern fn(f64) -> f64> =
132     ///         lib.get(b"awesome_function\0").unwrap();
133     ///     awesome_function(0.42);
134     /// }
135     /// ```
136     ///
137     /// A static variable may also be loaded and inspected:
138     ///
139     /// ```no_run
140     /// # use ::libloading::{Library, Symbol};
141     /// # let lib = unsafe { Library::new("/path/to/awesome.module").unwrap() };
142     /// unsafe {
143     ///     let awesome_variable: Symbol<*mut f64> = lib.get(b"awesome_variable\0").unwrap();
144     ///     **awesome_variable = 42.0;
145     /// };
146     /// ```
get<'lib, T>(&'lib self, symbol: &[u8]) -> Result<Symbol<'lib, T>, Error>147     pub unsafe fn get<'lib, T>(&'lib self, symbol: &[u8]) -> Result<Symbol<'lib, T>, Error> {
148         self.0.get(symbol).map(|from| Symbol::from_raw(from, self))
149     }
150 
151     /// Unload the library.
152     ///
153     /// This method might be a no-op, depending on the flags with which the `Library` was opened,
154     /// what library was opened or other platform specifics.
155     ///
156     /// You only need to call this if you are interested in handling any errors that may arise when
157     /// library is unloaded. Otherwise the implementation of `Drop` for `Library` will close the
158     /// library and ignore the errors were they arise.
159     ///
160     /// The underlying data structures may still get leaked if an error does occur.
close(self) -> Result<(), Error>161     pub fn close(self) -> Result<(), Error> {
162         self.0.close()
163     }
164 }
165 
166 impl fmt::Debug for Library {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result167     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168         self.0.fmt(f)
169     }
170 }
171 
172 impl From<imp::Library> for Library {
from(lib: imp::Library) -> Library173     fn from(lib: imp::Library) -> Library {
174         Library(lib)
175     }
176 }
177 
178 impl From<Library> for imp::Library {
from(lib: Library) -> imp::Library179     fn from(lib: Library) -> imp::Library {
180         lib.0
181     }
182 }
183 
184 unsafe impl Send for Library {}
185 unsafe impl Sync for Library {}
186 
187 /// Symbol from a library.
188 ///
189 /// This type is a safeguard against using dynamically loaded symbols after a `Library` is
190 /// unloaded. The primary method to create an instance of a `Symbol` is via [`Library::get`].
191 ///
192 /// The `Deref` trait implementation allows the use of `Symbol` as if it was a function or variable
193 /// itself, without taking care to “extract” the function or variable manually most of the time.
194 ///
195 /// [`Library::get`]: Library::get
196 #[cfg_attr(libloading_docs, doc(cfg(any(unix, windows))))]
197 pub struct Symbol<'lib, T: 'lib> {
198     inner: imp::Symbol<T>,
199     pd: marker::PhantomData<&'lib T>,
200 }
201 
202 impl<'lib, T> Symbol<'lib, T> {
203     /// Extract the wrapped `os::platform::Symbol`.
204     ///
205     /// # Safety
206     ///
207     /// Using this function relinquishes all the lifetime guarantees. It is up to the developer to
208     /// ensure the resulting `Symbol` is not used past the lifetime of the `Library` this symbol
209     /// was loaded from.
210     ///
211     /// # Examples
212     ///
213     /// ```no_run
214     /// # use ::libloading::{Library, Symbol};
215     /// unsafe {
216     ///     let lib = Library::new("/path/to/awesome.module").unwrap();
217     ///     let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
218     ///     let symbol = symbol.into_raw();
219     /// }
220     /// ```
into_raw(self) -> imp::Symbol<T>221     pub unsafe fn into_raw(self) -> imp::Symbol<T> {
222         self.inner
223     }
224 
225     /// Wrap the `os::platform::Symbol` into this safe wrapper.
226     ///
227     /// Note that, in order to create association between the symbol and the library this symbol
228     /// came from, this function requires a reference to the library.
229     ///
230     /// # Safety
231     ///
232     /// The `library` reference must be exactly the library `sym` was loaded from.
233     ///
234     /// # Examples
235     ///
236     /// ```no_run
237     /// # use ::libloading::{Library, Symbol};
238     /// unsafe {
239     ///     let lib = Library::new("/path/to/awesome.module").unwrap();
240     ///     let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
241     ///     let symbol = symbol.into_raw();
242     ///     let symbol = Symbol::from_raw(symbol, &lib);
243     /// }
244     /// ```
from_raw<L>(sym: imp::Symbol<T>, library: &'lib L) -> Symbol<'lib, T>245     pub unsafe fn from_raw<L>(sym: imp::Symbol<T>, library: &'lib L) -> Symbol<'lib, T> {
246         let _ = library; // ignore here for documentation purposes.
247         Symbol {
248             inner: sym,
249             pd: marker::PhantomData,
250         }
251     }
252 }
253 
254 impl<'lib, T> Symbol<'lib, Option<T>> {
255     /// Lift Option out of the symbol.
256     ///
257     /// # Examples
258     ///
259     /// ```no_run
260     /// # use ::libloading::{Library, Symbol};
261     /// unsafe {
262     ///     let lib = Library::new("/path/to/awesome.module").unwrap();
263     ///     let symbol: Symbol<Option<*mut u32>> = lib.get(b"symbol\0").unwrap();
264     ///     let symbol: Symbol<*mut u32> = symbol.lift_option().expect("static is not null");
265     /// }
266     /// ```
lift_option(self) -> Option<Symbol<'lib, T>>267     pub fn lift_option(self) -> Option<Symbol<'lib, T>> {
268         self.inner.lift_option().map(|is| Symbol {
269             inner: is,
270             pd: marker::PhantomData,
271         })
272     }
273 }
274 
275 impl<'lib, T> Clone for Symbol<'lib, T> {
clone(&self) -> Symbol<'lib, T>276     fn clone(&self) -> Symbol<'lib, T> {
277         Symbol {
278             inner: self.inner.clone(),
279             pd: marker::PhantomData,
280         }
281     }
282 }
283 
284 // FIXME: implement FnOnce for callable stuff instead.
285 impl<'lib, T> ops::Deref for Symbol<'lib, T> {
286     type Target = T;
deref(&self) -> &T287     fn deref(&self) -> &T {
288         ops::Deref::deref(&self.inner)
289     }
290 }
291 
292 impl<'lib, T> fmt::Debug for Symbol<'lib, T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result293     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
294         self.inner.fmt(f)
295     }
296 }
297 
298 unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {}
299 unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {}
300