原始指针将空值从Rust传递到C [英] Raw pointer turns null passing from Rust to C

查看:160
本文介绍了原始指针将空值从Rust传递到C的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从rust中的C函数上检索原始指针,并将该原始指针用作另一个库中另一个C函数中的参数.当我传递原始指针时,我在C端最终得到一个NULL指针.

I'm attempting to retrieve a raw pointer from on C function in rust, and use that same raw pointer as an argument in another C function from another library. When I pass the raw pointer, I end up with a NULL pointer on the C side.

我曾尝试对问题进行简化,但是当我这样做时,它会按我期望的那样工作-

I have tried to make a simplified version of my issue, but when I do it works as I would expect it to -

C代码-

struct MyStruct {
    int value;
};

struct MyStruct * get_struct() {
    struct MyStruct * priv_struct = (struct MyStruct*) malloc( sizeof(struct MyStruct));

    priv_struct->value = 0;
    return priv_struct;
}

void put_struct(struct MyStruct *priv_struct) {
    printf("Value - %d\n", priv_struct->value);
}

铁锈代码-

#[repr(C)]
struct MyStruct {
    value: c_int,
}

extern {
    fn get_struct() -> *mut MyStruct;
}

extern {
    fn put_struct(priv_struct: *mut MyStruct) -> ();
}

fn rust_get_struct() -> *mut MyStruct {
    let ret = unsafe { get_struct() };
    ret
}

fn rust_put_struct(priv_struct: *mut MyStruct) {
    unsafe { put_struct(priv_struct) };
}

fn main() {
    let main_struct = rust_get_struct();
    rust_put_struct(main_struct);
}

运行此命令时,将得到Value-0的输出

When I run this I get the output of Value - 0

~/Dev/rust_test$ sudo ./target/debug/rust_test 
Value - 0
~/Dev/rust_test$

但是,当尝试针对DPDK库执行此操作时,我以相同的方式检索并传递了原始指针,但遇到了段错误.如果我使用gdb进行调试,则可以看到我在Rust端传递了一个指针,但是在C端看到了NULL-

However, when trying to do this against a DPDK library, I retrieve and pass a raw pointer in the the same way but get a segfault. If I use gdb to debug, I can see that I'm passing a pointer on the Rust side, but I see it NULL on the C side -

(gdb) frame 0
#0  rte_eth_rx_queue_setup (port_id=0 '\000', rx_queue_id=<optimized out>, nb_rx_desc=<optimized out>, socket_id=0, rx_conf=0x0, mp=0x0)
   at /home/kenton/Dev/dpdk-16.07/lib/librte_ether/rte_ethdev.c:1216
1216    if (mp->private_data_size < sizeof(struct rte_pktmbuf_pool_private)) {

(gdb) frame 1
#1  0x000055555568953b in dpdk::ethdev::dpdk_rte_eth_rx_queue_setup (port_id=0 '\000', rx_queue_id=0, nb_tx_desc=128, socket_id=0, rx_conf=None, 
   mb=0x7fff3fe47640) at /home/kenton/Dev/dpdk_ffi/src/ethdev/mod.rs:32
32     let retc: c_int = unsafe {ffi::rte_eth_rx_queue_setup(port_id as uint8_t,

在第1帧中, mb 有一个地址,正在通过.在第0帧中,库中的接收函数将其显示为 mp 的0x0.

In frame 1, mb has an address and is being passed. In frame 0 the receiving function in the library is showing it as 0x0 for mp.

我的接收指针的代码-

let mb = dpdk_rte_pktmbuf_pool_create(CString::new("MBUF_POOL").unwrap().as_ptr(),
       (8191 * nb_ports) as u32 , 250, 0, 2176, dpdk_rte_socket_id());

这将调用一个ffi库-

This calls into an ffi library -

pub fn dpdk_rte_pktmbuf_pool_create(name: *const c_char,
                               n: u32,
                               cache_size: u32,
                               priv_size: u16,
                               data_room_size: u16,
                               socket_id: i32) -> *mut rte_mempool::ffi::RteMempool {
    let ret: *mut rte_mempool::ffi::RteMempool = unsafe {
        ffi::shim_rte_pktmbuf_pool_create(name,
                                          n as c_uint,
                                          cache_size as c_uint,
                                          priv_size as uint16_t,
                                          data_room_size as uint16_t,
                                          socket_id as c_int)
    };
    ret
}

ffi-

extern {
    pub fn shim_rte_pktmbuf_pool_create(name: *const c_char,
                                        n: c_uint,
                                        cache_size: c_uint,
                                        priv_size: uint16_t,
                                        data_room_size: uint16_t,
                                        socket_id: c_int) -> *mut rte_mempool::ffi::RteMempool;
}

C函数-

struct rte_mempool *
rte_pktmbuf_pool_create(const char *name, unsigned n,
    unsigned cache_size, uint16_t priv_size, uint16_t data_room_size,
    int socket_id);

当我传递指针时,它看起来与上面的简化版本相同.我的变量 mb 包含一个原始指针,该指针已传递给另一个函数-

When I pass the pointer, it looks much the same as my simplified version up above. My variable mb contains a raw pointer that I pass to another function -

ret = dpdk_rte_eth_rx_queue_setup(port,q,128,0,None,mb);

ffi库-

pub fn dpdk_rte_eth_rx_queue_setup(port_id: u8,
                                   rx_queue_id: u16,
                                   nb_tx_desc: u16,
                                   socket_id: u32,
                                   rx_conf: Option<*const ffi::RteEthRxConf>,
                                   mb_pool: *mut rte_mempool::ffi::RteMempool ) -> i32 {
    let retc: c_int = unsafe {ffi::rte_eth_rx_queue_setup(port_id as uint8_t,
                                                          rx_queue_id as uint16_t,
                                                          nb_tx_desc as uint16_t,
                                                          socket_id as c_uint,
                                                          rx_conf,
                                                          mb)};
    let ret: i32 = retc as i32;
    ret
}

ffi-

extern {
    pub fn rte_eth_rx_queue_setup(port_id: uint8_t,
                              rx_queue_id: uint16_t,
                              nb_tx_desc: uint16_t,
                              socket_id: c_uint,
                              rx_conf: Option<*const RteEthRxConf>,
                              mb: *mut rte_mempool::ffi::RteMempool ) -> c_int;
}

C函数-

int
rte_eth_rx_queue_setup(uint8_t port_id, uint16_t rx_queue_id,
               uint16_t nb_rx_desc, unsigned int socket_id,
               const struct rte_eth_rxconf *rx_conf,
               struct rte_mempool *mp);

我很抱歉,但我觉得我缺少一些简单的东西,并且无法弄清楚.我检查了传递的每个字段的结构对齐方式,甚至看到了按预期接收的指针的值-

I apologize for the length, but I feel like I'm missing something simple and haven't been able to figure it out. I've checked struct alignment for each field that is being passed, and I even see values for the pointer that is received as I'd expect -

(gdb) frame 1
#1  0x000055555568dcf4 in dpdk::ethdev::dpdk_rte_eth_rx_queue_setup (port_id=0 '\000', rx_queue_id=0, nb_tx_desc=128, socket_id=0, rx_conf=None, 
    mb=0x7fff3fe47640) at /home/kenton/Dev/dpdk_ffi/src/ethdev/mod.rs:32
32      let retc: c_int = unsafe {ffi::rte_eth_rx_queue_setup(port_id as uint8_t,

(gdb) print *mb
$1 = RteMempool = {name = "MBUF_POOL", '\000' <repeats 22 times>, pool_union = PoolUnionStruct = {data = 140734245862912}, pool_config = 0x0, 
  mz = 0x7ffff7fa4c68, flags = 16, socket_id = 0, size = 8191, cache_size = 250, elt_size = 2304, header_size = 64, trailer_size = 0, 
  private_data_size = 64, ops_index = 0, local_cache = 0x7fff3fe47700, populated_size = 8191, elt_list = RteMempoolObjhdrList = {
    stqh_first = 0x7fff3ebc7f68, stqh_last = 0x7fff3fe46ce8}, nb_mem_chunks = 1, mem_list = RteMempoolMemhdrList = {stqh_first = 0x7fff3ebb7d80, 
stqh_last = 0x7fff3ebb7d80}, __align = 0x7fff3fe47700}

关于为什么指针在C端变为NULL的任何想法?

Any ideas on why the pointer is turning to NULL on the C side?

推荐答案

CString::new("…").unwrap().as_ptr()不起作用. CString是临时的,因此as_ptr()调用返回该临时的内部指针,当您使用它时,它可能会悬空.只要您不使用指针,这就符合Rust的安全性定义,这是安全"的,但最终您会在unsafe块中使用它.您应该将字符串绑定到变量,然后在该变量上使用as_ptr.

CString::new("…").unwrap().as_ptr() does not work. The CString is temporary, hence the as_ptr() call returns the inner pointer of that temporary, which will likely be dangling when you use it. This is "safe" per Rust's definition of safety as long as you don't use the pointer, but you eventually do so in a unsafe block. You should bind the string to a variable and use as_ptr on that variable.

这是一个常见的问题,甚至还有提出了解决CStr{,ing}的建议避免这种情况的API .

This is such a common problem, there is even a proposal to fix the CStr{,ing} API to avoid it.

另外,原始指针本身可以为空,因此const struct rte_eth_rxconf *的Rust FFI等效项为*const ffi::RteEthRxConf,而不是Option<*const ffi::RteEthRxConf>.

Additionally raw pointer are nullable by themselves, so the Rust FFI equivalent of const struct rte_eth_rxconf * would be *const ffi::RteEthRxConf, not Option<*const ffi::RteEthRxConf>.

这篇关于原始指针将空值从Rust传递到C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆