#内存泄漏 #指针 #守护 #传递 #原始指针 #边界 #帮助

passable_guard

一个守护者,帮助您捕获跨 FFI 边界传递的指针泄漏

1 个稳定版本

1.0.0 2021 年 7 月 28 日

#2402 in Rust 模式

Apache-2.0 协议

13KB
76 代码行

Passable Guard

Passable Guard 链接库提供了一种在运行时检查 FFI 内存泄漏的方法。

这是通过提供一个 PassableContainer 类来实现的,该类封装了一个可以转换为原始指针以跨 FFI 边界传递的 Passable 对象。

在转换 Passable 时,该 PassableContainer 将原始指针与 PassableGuard 结合。

如果该 PassableGuard 在与原始指针重新组合之前被丢弃,它将引发 panic。

这样,您至少会得到一个 panic,而不是内存泄漏

示例

对于这个示例,我们将创建一个 CString 并将其传递给一个虚构的 FFI 函数 setName,使用 PassableContainer 防止内存泄漏

use std::ffi::CString;
use passable_guard::PassableContainer;

extern "C" {
    /// Takes a pointer to a NULL-Terminated utf-8 string
    /// Returns 0 on failure and >0 on success
    fn setName(ptr: *mut u8) -> u8;
}

fn passable_example(name: CString) -> Result<(),()> {
    let passable = PassableContainer::new(name); // Create the Container from the name CString

    let (guard, ptr) = passable.pass(); // Convert the Container into a raw pointer (and get the guard for it as well)

    let result = unsafe {
         setName(ptr) // Call the FFI function and give it our pointer
    };

    unsafe {
        // Reconstitute the Guard and Pointer back into a Container
        // The pointers will be the same since we use the pointer we got from the pass method
        // This might cause UB if setName modifies the Memory
        guard.reconstitute(ptr).unwrap();
    }
    drop(ptr); // Drop the Pointer so we do not use it again

    return if result == 0 {
        Err(())
    }
    else {
        Ok(())
    }
}

让我们看看一个会引发 panic 的示例

use std::ffi::CString;
use passable_guard::PassableContainer;

extern "C" {
    /// Takes a pointer to a NULL-Terminated utf-8 string
    /// Returns 0 on failure and >0 on success
    fn setName(ptr: *mut u8) -> u8;
}

fn passable_example(name: CString) -> Result<(),()> {
    let passable = PassableContainer::new(name); // Create the Container from the name CString

    let (guard, ptr) = passable.pass(); // Convert the Container into a raw pointer (and get the guard for it as well)

    let result = unsafe {
         setName(ptr) // Call the FFI function and give it our pointer
    };

    // Drop the Pointer so we do not use it again
    // This means that we cannot possibly reconstitute the Guard and pointer
    drop(ptr);

    return if result == 0 {
        Err(())
    }
    else {
        Ok(())
    }
    // The Function will panic here since the Guard has been dropped without being reconstituted
    // Without the Guard, we would have now subtly leaked the String Memory
}

无运行时依赖