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