nagisa / rust_libloading

Bindings around the platform's dynamic library loading primitives with greatly improved memory safety.
https://docs.rs/libloading
ISC License
1.22k stars 100 forks source link

load a dynamic library crash #143

Closed FlorentinoJink closed 5 months ago

FlorentinoJink commented 5 months ago

This my rust code

use libc::{size_t, wchar_t};
use widestring::WideString;

const UTILITIES: &str = "utilities.dll";
const MAX_PATH: usize = 260;

pub fn test() -> Result<size_t, Box<dyn std::error::Error>> {
    let mut dll_path = std::env::current_dir().unwrap();
    dll_path.push(UTILITIES);
    unsafe {
        let lib = libloading::Library::new(dll_path)?;
        let return_value: libloading::Symbol<
            extern "C" fn(*const wchar_t, size_t, *mut wchar_t, size_t) -> size_t,
        > = lib.get(b"return_value")?;

        let filename = WideString::from("hahah");
        let file_size = filename.len();
        let file_ptr = filename.as_ptr();

        // let mut content: [u16; MAX_PATH] = [0; MAX_PATH];
        // let company = &mut content as *mut _ as *mut wchar_t;
        let mut company2 = WideString::with_capacity(MAX_PATH).as_mut_ptr();
        let mut company = WideString::from("TotototototototototototototototototoT").as_mut_ptr();
        let return_size = return_value(file_ptr, file_size, company, 30);

        std::ptr::copy_nonoverlapping(company, company2, 30);
        println!("company1: {:?}", WideString::from_ptr(company,30));
        println!("company2: {:?}", WideString::from_ptr(company2,30));

        Ok(1)
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    std::env::set_current_dir(std::env::current_exe()?.parent().unwrap())?;
    // let binding = WideString::from("D:\\workspace\\rust_load\\filemaster.exe");
    // let name = get_company_sign(binding)?;
    // println!("name: {:?}, size: {}", name, name.len());
    println!("running");
    test()?;
    println!("after call test");
    Ok(())
}

this my toml

[package]
name = "rust_load"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
libloading = "0.8"
widestring = "1.0.2"
libc = "0.2.139"

and this my windows cpp dll

UTILITIES_API size_t return_value(const wchar_t* name, size_t name_size, wchar_t* company_name, size_t company_size)
{
    return 11;
}

I just return a value. when I run it, as long as I operate on the pointer created using WideString::with_capacity, the dynamic library unloads and crashes, but if I use an array, there is no such issue. if I load the dynamic library, it crashes.

image

if not dynamic library, not crash image

Why does memory operation crash after loading a dynamic library, and why doesn't it crash when switching to an array?

nagisa commented 5 months ago

Try

let mut company2_ws = WideString::with_capacity(MAX_PATH);
let company2 = company2_ws.as_mut_ptr()

instead of

let mut company2 = WideString::with_capacity(MAX_PATH).as_mut_ptr();

and similarly for other instances of this. The way you're doing it right now the WideString is allocated, the mutable pointer is obtained from it and then the WideString is freed at the end of the statement, because it itself is not assigned to anything. Then the code goes on to use-after-free this now-dangling pointer.

As a general rule of thumb I would recommend converting to raw pointers at the very last moment (e.g. in a function call arguments), as this way you get most out of the static analyses that Rust provides -- raw pointers are not included into those!)

All that said, these issues are not libloading specifically. I would like to point you at users.rust-lang.org or a similar forum for questions about use of Rust.

Thanks!