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

Rust跨语言库字符串内存双端安全释放实现咨询

解决方案:区分所有权实现跨场景内存管理

完全可行,不用在Rust端手动调用free函数,核心思路是给结构体添加所有权标记,区分内存是由Rust自动管理还是交由C/C++手动释放,从而避免双free或内存泄漏问题。

问题根源

你之前触发双free的原因是:结构体里的裸指针没有所有权标记,Drop trait和C端的free_shared_string都尝试释放同一块内存;而不加Drop时,Rust端无法自动回收into_raw()转出的内存,导致泄漏。

具体实现

第一步,给结构体添加所有权标记,并加上#[repr(C)]确保C语言能正确解析结构体布局(FFI必备):

use std::{ffi::{CString, CStr}, os::raw::c_char};

#[repr(C)]
pub struct SomeData {
    pub data: *const c_char,
    owned: bool, // 标记内存是否由Rust拥有所有权
}

第二步,实现Drop trait,仅当Rust拥有所有权时才释放内存:

impl Drop for SomeData {
    fn drop(&mut self) {
        // 只有当Rust拥有所有权且指针非空时,才回收内存
        if self.owned && !self.data.is_null() {
            unsafe {
                // from_raw会重新获取CString的所有权,drop时自动释放内存
                let _ = CString::from_raw(self.data.cast_mut());
            }
        }
    }
}

第三步,区分构造函数:给Rust内部使用的构造函数设置owned: true,给FFI提供的构造函数设置owned: false(所有权转移给C端):

impl SomeData {
    // Rust内部使用的构造函数,自动管理内存
    pub fn new(s: &str) -> Self {
        let c_str = CString::new(s).expect("字符串包含空字节");
        SomeData {
            data: c_str.into_raw(),
            owned: true,
        }
    }

    // FFI构造函数:接收C字符串,返回结构体指针,所有权转移给C端
    #[no_mangle]
    pub extern "C" fn some_data_new(s: *const c_char) -> *mut SomeData {
        let rust_str = unsafe { CStr::from_ptr(s).to_str().expect("无效的C字符串") };
        let c_str = CString::new(rust_str).expect("字符串包含空字节");
        let data = c_str.into_raw();
        // 用Box包装后转成裸指针,C端拿到后需要手动释放结构体本身
        Box::into_raw(Box::new(SomeData { data, owned: false }))
    }
}

第四步,修正FFI的free函数,确保同时回收字符串内存和结构体本身:

#[no_mangle]
pub extern "C" fn free_shared_string(ptr: *mut SomeData) {
    if ptr.is_null() {
        return;
    }
    // 从裸指针恢复Box,确保结构体本身被正确释放
    let mut obj = unsafe { Box::from_raw(ptr) };
    if !obj.data.is_null() {
        unsafe {
            let _ = CString::from_raw(obj.data.cast_mut());
        }
        obj.data = std::ptr::null(); // 避免悬空指针
    }
}

使用说明

  • Rust端:直接用SomeData::new("xxx")创建,无需手动释放,Drop会自动回收内存。
  • C/C++端:通过some_data_new创建结构体指针,使用完后调用free_shared_string释放内存(包括字符串和结构体本身)。

这样既解决了Rust端的内存泄漏问题,又避免了C端和Rust端的双free冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 03:48:36