我试图从 rust 中的 C 函数中检索原始指针,并在另一个库中的另一个 C 函数中使用相同的原始指针作为参数。当我传递原始指针时,我最终在 C 端得到了一个 NULL 指针。
我试图制作我的问题的简化版本,但是当我这样做时,它会像我期望的那样工作 -
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);
}
Run Code Online (Sandbox Code Playgroud)
锈代码 -
#[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);
}
Run Code Online (Sandbox Code Playgroud)
当我运行它时,我得到 Value - 0 的输出
~/Dev/rust_test$ sudo ./target/debug/rust_test
Value - 0
~/Dev/rust_test$
Run Code Online (Sandbox Code Playgroud)
但是,当尝试针对 DPDK 库执行此操作时,我以相同的方式检索并传递原始指针,但出现段错误。如果我使用 gdb 进行调试,我可以看到我在 Rust 端传递了一个指针,但我在 C 端看到它为 NULL -
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);
}
Run Code Online (Sandbox Code Playgroud)
在第 1 帧中,mb有一个地址并且正在被传递。在第 0 帧中,库中的接收函数将mp显示为 0x0 。
我接收指针的代码 -
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());
Run Code Online (Sandbox Code Playgroud)
这调用了一个 ffi 库 -
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
}
Run Code Online (Sandbox Code Playgroud)
菲 -
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;
}
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
当我传递指针时,它看起来与我上面的简化版本非常相似。我的变量mb包含一个我传递给另一个函数的原始指针 -
ret = dpdk_rte_eth_rx_queue_setup(port,q,128,0,None,mb);
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
菲 -
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;
}
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
我为长度道歉,但我觉得我错过了一些简单的东西并且无法弄清楚。我已经检查了正在传递的每个字段的结构对齐,我什至看到了我所期望的指针的值 -
#[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);
}
Run Code Online (Sandbox Code Playgroud)
关于为什么指针在 C 端变成 NULL 的任何想法?
CString::new("…").unwrap().as_ptr()
不起作用。这CString
是临时的,因此as_ptr()
调用返回该临时的内部指针,当您使用它时可能会悬空。只要您不使用指针,根据 Rust 的安全定义,这是“安全的”,但最终在unsafe
块中使用。您应该将字符串绑定到变量并使用as_ptr
在该变量上。
这是一个很常见的问题,甚至有人建议修复CStr{,ing}
API 以避免它。
此外,原始指针本身可以为空,因此 Rust FFI 的等价物 const struct rte_eth_rxconf *
将是*const ffi::RteEthRxConf
,而不是Option<*const ffi::RteEthRxConf>
。