STATUS_HEAP_CORRUPTION error occurred when send data from Rust to C# DLL

1

I have been facing an issue when I send the string data from Rust to C# DLL. Rust exe will show the following error.

error: process didn't exit successfully: target\release\test.exe (exit code: 0xc0000374, STATUS_HEAP_CORRUPTION)

The Rust exe will crash after I sent the data for a few times (No exact pattern).

Below is the code on how the Rust communicate with C# DLL.

extern crate libloading;

fn call_dynamic(arg_1_str: &str, arg_2_int: i32) -> Result<i32, Box<dyn std::error::Error>> {

    let arg_1_c_str = CString::new(arg_str_1).unwrap();

    // This is intended 
    let arg_3_c_str = CString::new("").unwrap();

    let arg_1_c_char = arg_1_c_str.as_ptr();
    let arg_3_c_char = arg_3_c_str.as_ptr();

    let lib = libloading::Library::new("Test.dll").unwrap();
    unsafe {
        let func: libloading::Symbol<
            unsafe fn(
                arg_1: *const c_char,
                arg_2: i32,
                arg_3: *const c_char,
            ) -> i32,
        > = lib
            .get(b"GetStatus")
            .unwrap();

        Ok(func(arg_1_c_char, arg_2_int, arg_3_c_char))
    }
}

The library that used to communicate with external DLL is libloading.

What could possible cause this error to be happened and is there any way to overcome the issue? Your help is much appreciated.

Note: I have no access to the source code of the C# DLL. Hence, I have no idea what is happening inside.

Here's some Java code that works. I'm trying to do the same thing in Rust:

public interface TestDLL extends Library { 
    int GetStatus (String arg1, int arg2, String arg3);
}

public int GetStatusFromDLL (String arg1, int arg2) {
    TestDLL test_dll = (TestDLL)Native.loadLibrary ("Test", TestDLL.class);
    return test_dll.GetStatus (arg1, arg2, null);
}
c#
dll
rust
asked on Stack Overflow Jan 27, 2021 by Ng Yk • edited Jan 28, 2021 by Jmb

1 Answer

0

This issue is solved by changing the third argument arg_3_c_str from an empty string to null pointer ptr::null(). The final solution is as below.

fn call_dynamic(arg_1_str: &str, arg_2_int: i32) -> Result<i32, Box<dyn std::error::Error>> {

    let arg_1_c_str = CString::new(arg_str_1).unwrap();
    let arg_1_c_char = arg_1_c_str.as_ptr();

    let lib = libloading::Library::new("Test.dll").unwrap();
    unsafe {
        let func: libloading::Symbol<
            unsafe fn(
                arg_1: *const c_char,
                arg_2: i32,
                arg_3: *const c_char,
            ) -> i32,
        > = lib
            .get(b"GetStatus")
            .unwrap();

        Ok(func(arg_1_c_char, arg_2_int, ptr::null()))
    }
}

All credits goes to @Jmb as he pointed out the difference between the Rust and Java implementations.

But, still there is another interesting point to discuss why passing in an empty string instead of null pointer will cause STATUS_HEAP_CORRUPTION error.

answered on Stack Overflow Jan 28, 2021 by Ng Yk

User contributions licensed under CC BY-SA 3.0