rust - 如何在没有 Box::from_raw 的情况下将 *mut *mut c_void 转换为 &str?

标签 rust ffi

我一直在尝试用 Rust 编写 Redis 模块。这是我第一次尝试使用 Rust FFI 和绑定(bind)。如何在 Rust 中调用此方法并最终得到数据值而不破坏 Redis 指针?

extern "C" {
    pub static mut RedisModule_GetTimerInfo: ::std::option::Option<
        unsafe extern "C" fn(
            ctx: *mut RedisModuleCtx,
            id: RedisModuleTimerID,
            remaining: *mut u64,
            data: *mut *mut ::std::os::raw::c_void,
        ) -> ::std::os::raw::c_int,
    >;
}

请参阅RedisModule_GetTimerInfo API Docs了解更多详情。

我最终让它工作,但如果我使用相同的 id 调用它两次,它会抛出错误:

let mut ms = 0 as u64;
let val = "";
let ptr = Box::into_raw(Box::new(&mut val)) as *mut *mut c_void;
let ok = unsafe { RedisModule_GetTimerInfo.unwrap()(ctx, id, &mut ms, ptr) };
let mut data: Option<String> = None;
if ok == 0 {
    let val = unsafe { Box::from_raw(*ptr as *mut &str) };
    // trim nul bytes
    data = Some(val.trim_matches(char::from(0)).to_string());
}

这不起作用,因为 Box::from_raw 拥有原始指针,并且当盒子被放下时指针会被销毁。

我在不使用 Box::into_raw 和 Box::from_raw 的情况下尝试了无数种方法来完成这项工作,但每次它们要么导致 Redis 崩溃,要么最终成为一个我不知道如何转换为 &str 的指针。

更新:我最初有一个使用 RedisModule_StopTimer 的示例,这是一个错误。已更正为使用我询问的方法。

最佳答案

我是 redismodule-rs 的维护者之一crate,它提供了用于编写 Redis 模块的高级 Rust API。

根据您的问题,我考虑以安全的方式将这些计时器 API 添加到包中,并在完成后将代码推送到存储库。

以下代码展示了如何安全地检索数据:

// Create local variables to hold the returned values
let mut remaining: u64 = 0;
let mut data: *mut c_void = std::ptr::null_mut();

// Call the API and retrieve the values into the local variables
let status = unsafe {
    RedisModule_GetTimerInfo.unwrap()(ctx, timer_id, &mut remaining, &mut data)
};

if status == REDISMODULE_OK {
    // Cast the *mut c_void supplied by the Redis API to 
    // a raw pointer of our custom type:
    let data = data as *mut T; // T is the type of the data, e.g. String

    // Dereference the raw pointer (we know this is safe,
    // since Redis should return our original pointer which
    // we know to be good), and turn in into a safe reference:
    let data = unsafe { &*data };

    println!("Remaining: {}, data: {:?}", remaining, data);
}

关于rust - 如何在没有 Box::from_raw 的情况下将 *mut *mut c_void 转换为 &str?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60963130/

相关文章:

ffi - Nim 从 C 头文件导入 typedef

Rust 中的 C 抽象数据类型

rust - 如何将 tera::Error 转换为 actix_web::Error?

hashmap - VacantEntry 未在名为 set 的范围内实现任何方法

iterator - 修改 `iter_mut().map(..)` 中的 self ,又名可变函数集合操作

generics - 如何将 ndarray 中的元素与 Rust 中的泛型相乘?

c - 从 Ruby 访问 C 项目上的 dll 函数

types - 是否可以将闭包分配给 impl Fn() 类型的变量?

c++ - 为什么 Ruby FFI 不附加自定义共享对象库中的函数

C++ 和 Lua - 不 protected 错误(错误的回调)?这怎么可能