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