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 | /// ``` |
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 | /// ``` |
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. |
161 | pub fn close(self) -> Result<(), Error> { |
162 | self.0.close() |
163 | } |
164 | } |
165 | |
166 | impl fmt::Debug for Library { |
167 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
168 | self.0.fmt(f) |
169 | } |
170 | } |
171 | |
172 | impl From<imp::Library> for Library { |
173 | fn from(lib: imp::Library) -> Library { |
174 | Library(lib) |
175 | } |
176 | } |
177 | |
178 | impl From<Library> for imp::Library { |
179 | 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 | /// ``` |
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 | /// ``` |
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 | /// ``` |
267 | pub fn lift_option(self) -> Option<Symbol<'lib, T>> { |
268 | self.inner.lift_option().map(|is: Symbol| Symbol { |
269 | inner: is, |
270 | pd: marker::PhantomData, |
271 | }) |
272 | } |
273 | } |
274 | |
275 | impl<'lib, T> Clone for 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; |
287 | fn deref(&self) -> &T { |
288 | ops::Deref::deref(&self.inner) |
289 | } |
290 | } |
291 | |
292 | impl<'lib, T> fmt::Debug for Symbol<'lib, T> { |
293 | 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 | |