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 /// ``` new<P: AsRef<OsStr>>(filename: P) -> Result<Library, Error>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 /// ``` get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, Error>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. close(self) -> Result<(), Error>162 pub fn close(self) -> Result<(), Error> { 163 self.0.close() 164 } 165 } 166 167 impl fmt::Debug for Library { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result168 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 169 self.0.fmt(f) 170 } 171 } 172 173 impl From<imp::Library> for Library { from(lib: imp::Library) -> Library174 fn from(lib: imp::Library) -> Library { 175 Library(lib) 176 } 177 } 178 179 impl From<Library> for imp::Library { from(lib: Library) -> imp::Library180 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 /// ``` into_raw(self) -> imp::Symbol<T>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 /// ``` from_raw<L>(sym: imp::Symbol<T>, library: &'lib L) -> Symbol<'lib, T>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. try_as_raw_ptr(self) -> Option<*mut raw::c_void>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 /// ``` lift_option(self) -> Option<Symbol<'lib, T>>287 pub fn lift_option(self) -> Option<Symbol<'lib, T>> { 288 self.inner.lift_option().map(|is| Symbol { 289 inner: is, 290 pd: marker::PhantomData, 291 }) 292 } 293 } 294 295 impl<'lib, T> Clone for Symbol<'lib, T> { clone(&self) -> 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; deref(&self) -> &T307 fn deref(&self) -> &T { 308 ops::Deref::deref(&self.inner) 309 } 310 } 311 312 impl<T> fmt::Debug for Symbol<'_, T> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result313 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