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