为什么 Rust 原生库在调用函数时会随机崩溃?

hel*_*net 2 java crash rust jnr

在 Rust 中,我有一个压缩数组的函数:

fn create_bitvec(data: Box<[u8]>) -> [u8; 49152] {
    let mut bit_vector = [0u8; 49152];
    for (index, &value) in data.iter().enumerate() {
        let byte_index = (index * 4) / 8;
        let bit_index = (index * 4) % 8;
        let value_mask = 0b00001111 << bit_index;
        let shifted_value = (value << bit_index) & value_mask;
        bit_vector[byte_index] &= !value_mask;
        bit_vector[byte_index] |= shifted_value;
    }
    debug!("made it here. {:?}", bit_vector);
    bit_vector
}
Run Code Online (Sandbox Code Playgroud)

(很抱歉,如果函数的实现不好,但这不是这里的具体问题)。

该函数的使用方式如下:

pub fn create(data: Box<[u8]>) -> Chunk {
    assert_eq!(data.len(), FULL, "Data length doesn't match!");
    let bitvec = Chunk::create_bitvec(data);
    debug!("Got here 1!");
    let c = Chunk {
        data: Chunk::create_rle(bitvec),
    };
    debug!("Got here 2: {:?} {}!", c.data, c.data.len());
    c
}
Run Code Online (Sandbox Code Playgroud)

该程序用作 Java 的本机库。该结构体不直接使用,但仅使用extern "C" fnfrom公开一些关键函数lib.rs。当从 rust 调用 create 作为单元测试的一部分时,一切都按预期工作,但是当从 JVM 使用时,程序崩溃,没有额外的恐慌/调试信息,并带有退出代码-1073740940 (0xC0000374)。我根本无法理解的真正令人困惑的部分是,made it here使用正确的数组记录得很好,但程序在Got here 1记录之前崩溃了。以下是我已经尝试过的一些事情:

  • 验证数组长度

  • 验证数据是否适合该u8类型

  • 仅测试 Rust 的代码

我怀疑这个问题可能与内存有关,但我不确定,特别是因为我传递Xmx8G给了 JVM。

我用jnr-ffi的是当地人。

以下是相关 Rust 代码lib.rs

static CHUNK_STATE: Mutex<Cell<Option<ChunkManager>>> = Mutex::new(Cell::new(None));
#[no_mangle]
pub extern "C" fn chunk_build(x: i64, y: i64, arr: *const u8) {
    info!("Building chunk: {}, {}", x, y);
    unsafe {
        CHUNK_STATE.lock().get_mut().as_mut().expect("Not initialized!").build((x, y), Box::from_raw(slice::from_raw_parts_mut(arr as *mut u8, WIDTH * WIDTH * HEIGHT)));
    }
}
Run Code Online (Sandbox Code Playgroud)

以及它在 Java 中的用法:

public interface NativeLib {
    void chunk_build(int x, int y, byte[] arr);
}
Run Code Online (Sandbox Code Playgroud)
import jnr.ffi.LibraryLoader;

public class Natives {
    public static NativeLib INSTANCE;

    public static void init() {
        INSTANCE = LibraryLoader.create(NativeLib.class).load("C:\\Users\\*\\*\\*\\nativelib\\target\\release\\pathlib.dll");
        INSTANCE.init();
    }
}
Run Code Online (Sandbox Code Playgroud)

kmd*_*eko 5

您不应该用来Box处理从 Java 端获得的内存。Box当内存超出范围时,将尝试释放内存,但这会遇到错误,因为内存Box最初未分配。

相反,仅使用切片:

fn create_bitvec(data: &[u8]) -> [u8; 49152] {
    // ...
}

pub fn create(data: &[u8]) -> Chunk {
    // ...
}
Run Code Online (Sandbox Code Playgroud)
.build((x, y), slice::from_raw_parts_mut(arr as *mut u8, WIDTH * WIDTH * HEIGHT));
Run Code Online (Sandbox Code Playgroud)

以及您省略的使用它的任何其他代码。函数内的实现不应该(太多)改变,因为Box它相当透明。