You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust原生库被JVM调用时函数随机崩溃问题求助

Rust原生库通过JVM调用崩溃(错误码0xC0000374)的排查与解决

问题概述

Rust实现的数组压缩逻辑在单元测试中完全正常,但通过JVM(使用jnr-ffi)调用时,程序无恐慌/调试信息直接崩溃,退出码为-1073740940 (0xC0000374)。具体表现为:create_bitvec函数的"made it here"日志能正常输出且数组内容正确,但create函数中"Got here 1"日志输出前就崩溃。

相关代码

Rust侧核心实现

create_bitvec函数

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
}

create函数

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
}

暴露给JVM的C接口

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)));
    }
}

Java侧调用代码

NativeLib接口

public interface NativeLib {
    void chunk_build(int x, int y, byte[] arr);
}

加载库逻辑

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();
    }
}

已尝试的排查步骤

  • 验证输入数组长度符合预期
  • 确认输入数据适配u8类型
  • Rust单元测试覆盖核心逻辑,无异常

问题原因分析

错误码0xC0000374对应Windows系统的堆损坏(Heap Corruption),结合代码细节,核心问题集中在以下几点:

  1. 非法内存释放
    在chunk_build中,使用Box::from_raw(slice::from_raw_parts_mut(arr as *mut u8, ...))将JVM管理的byte[]内存转换为Rust的Box<[u8]>。Rust的Box会在生命周期结束时自动调用内存释放逻辑,但这块内存属于JVM堆,并非Rust分配器管理,直接释放会破坏JVM的堆结构,导致后续操作崩溃。

  2. 参数类型不匹配
    Java端传递的x、y是32位int类型,但Rust侧定义为64位i64。虽然日志中能输出x、y的值,但类型不匹配可能导致栈帧错乱,间接引发内存访问异常。

  3. 大数组栈分配风险
    create_bitvec返回的[u8; 49152]是栈上分配的数组(48KB),虽然Windows默认栈大小为1MB,但JVM调用原生函数时的栈空间可能受限,存在栈溢出隐患。

解决办法

1. 修复非法内存释放问题

不要直接将JVM内存转换为Rust的Box,而是复制数据到Rust管理的内存中:

#[no_mangle]
pub extern "C" fn chunk_build(x: i64, y: i64, arr: *const u8) {
    info!("Building chunk: {}, {}", x, y);
    unsafe {
        // 先从JVM内存中复制数据到Rust管理的Vec/Box
        let slice = slice::from_raw_parts(arr, WIDTH * WIDTH * HEIGHT);
        let data = slice.to_vec().into_boxed_slice();
        CHUNK_STATE.lock().get_mut().as_mut().expect("Not initialized!").build((x, y), data);
    }
}

2. 统一参数类型

确保Java与Rust的参数类型匹配,任选一种方案:

  • Rust侧改为32位整数:
    pub extern "C" fn chunk_build(x: i32, y: i32, arr: *const u8) {
        // ... 逻辑不变
    }
    
  • Java侧改为64位长整数:
    public interface NativeLib {
        void chunk_build(long x, long y, byte[] arr);
    }
    

3. 避免大数组栈分配

将create_bitvec的返回类型改为堆分配的Box<[u8]>,消除栈溢出风险:

fn create_bitvec(data: Box<[u8]>) -> Box<[u8]> {
    let mut bit_vector = vec![0u8; 49152].into_boxed_slice();
    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
}

验证建议

  1. 先修复内存释放问题,这是堆损坏的核心原因
  2. 测试时启用Rust的调试断言(debug模式编译),更容易捕获内存越界等问题
  3. 使用Windows的调试工具(如WinDbg)附加到JVM进程,查看崩溃时的调用栈,进一步定位问题

内容的提问来源于stack exchange,提问作者hello planet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 22:17:03