Skip to main content

symbols/
symbols.rs

1//! Loading a library and calling functions through borrowed symbols.
2//!
3//! Run with `cargo run --example symbols`.
4
5#![allow(clippy::multiple_unsafe_ops_per_block)]
6
7use std::ffi::{CStr, c_char, c_int};
8
9use dlsym::Library;
10
11#[cfg(any(target_os = "linux", target_os = "fullrust"))]
12const LIBM: &str = "libm.so.6";
13#[cfg(target_vendor = "apple")]
14const LIBM: &str = "/usr/lib/libm.dylib";
15#[cfg(windows)]
16const LIBM: &str = "ucrtbase.dll";
17#[cfg(target_os = "freebsd")]
18const LIBM: &str = "libm.so.5";
19#[cfg(not(any(
20    target_os = "linux",
21    target_os = "fullrust",
22    target_os = "freebsd",
23    target_vendor = "apple",
24    windows
25)))]
26const LIBM: &str = "libm.so";
27
28fn main() -> dlsym::Result<()> {
29    // SAFETY: the C math library's initialisers are trusted.
30    let libm = unsafe { Library::open(LIBM) }?;
31
32    // SAFETY: `cos` has this signature.
33    let cos = unsafe { libm.get::<unsafe extern "C" fn(f64) -> f64>(c"cos") }?;
34    // SAFETY: `cos` is defined for every `f64`.
35    println!("cos(0) = {}", unsafe { cos.call((0.0,)) });
36
37    // Variadic functions are called through `with`; the raw function
38    // pointer cannot escape the closure without `unsafe`.
39    #[cfg(not(windows))]
40    let libc = Library::this()?;
41    // SAFETY: msvcrt is a system library.
42    #[cfg(windows)]
43    let libc = unsafe { Library::open("msvcrt.dll") }?;
44    // SAFETY: `sprintf` has this signature.
45    let sprintf = unsafe {
46        libc.get::<unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int>(c"sprintf")
47    }?;
48    let mut buf = [0 as c_char; 64];
49    // SAFETY: the buffer is large enough and the format matches.
50    unsafe {
51        sprintf.with(|f| {
52            f(
53                buf.as_mut_ptr(),
54                c"%s has %d symbols".as_ptr(),
55                c"this example".as_ptr(),
56                2,
57            )
58        })
59    };
60    // SAFETY: `sprintf` NUL-terminated the buffer.
61    let text = unsafe { CStr::from_ptr(buf.as_ptr()) };
62    println!("{}", text.to_string_lossy());
63
64    // `cos` borrows `libm`: uncommenting this line makes the call below a
65    // compile error instead of a use-after-unload.
66    // drop(libm);
67    // SAFETY: as above.
68    println!("cos(pi) = {}", unsafe { cos.call((std::f64::consts::PI,)) });
69    Ok(())
70}