Le pointeur brut devient nul, passant de Rust à C

J’essaie de récupérer un pointeur brut d’une fonction C en rouille et d’utiliser ce même pointeur brut comme argument dans une autre fonction C d’une autre bibliothèque. Lorsque je passe le pointeur brut, je me retrouve avec un pointeur NULL du côté C.

J’ai essayé de faire une version simplifiée de mon problème, mais quand je le fais, ça fonctionne comme je le pensais –

Code 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); } 

Code de la rouille –

 #[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); } 

Quand je lance ceci, je reçois la sortie de Value – 0

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

Cependant, lorsque j’essaie de le faire contre une bibliothèque DPDK, je récupère et passe un pointeur brut de la même manière, mais j’obtiens une erreur de segmentation. Si j’utilise gdb pour déboguer, je peux voir que je passe un pointeur du côté Rust, mais je le vois NULL du côté C –

 (gdb) frame 0 #0 rte_eth_rx_queue_setup (port_id=0 '\000', rx_queue_id=, nb_rx_desc=, 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, 

Dans l’image 1, mb a une adresse et est en cours de transmission. Dans le cadre 0, la fonction de réception dans la bibliothèque indique 0x0 pour mp .

Mon code pour recevoir le pointeur –

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

Cela appelle une bibliothèque 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 } 

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; } 

Fonction 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); 

Lorsque je passe le pointeur, il ressemble beaucoup à ma version simplifiée ci-dessus. Ma variable mb contient un pointeur brut que je passe à une autre fonction –

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

bibliothèque 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, 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, mb: *mut rte_mempool::ffi::RteMempool ) -> c_int; } 

Fonction 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); 

Je m’excuse pour la longueur, mais je sens qu’il me manque quelque chose de simple et que je n’ai pas été en mesure de le comprendre. J’ai vérifié l’alignement de la structure pour chaque champ transmis et je vois même les valeurs du pointeur reçues comme je le pensais –

 (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' , 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} 

Des idées sur pourquoi le pointeur se tourne vers NULL du côté C?

CSsortingng::new("…").unwrap().as_ptr() ne fonctionne pas. La CSsortingng étant temporaire, l’appel as_ptr() renvoie le pointeur interne de cette as_ptr() temporaire, qui sera probablement suspendue lorsque vous l’utiliserez. Ceci est «sûr» selon la définition de sécurité de Rust tant que vous n’utilisez pas le pointeur, mais que vous le faites éventuellement dans un bloc unsafe . Vous devez lier la chaîne à une variable et utiliser as_ptr sur cette variable.

C’est un problème si courant qu’il existe même une proposition pour corriger l’ CStr{,ing} afin de l’éviter .

De plus, les pointeurs bruts sont nuls par eux-mêmes. L’équivalent Rust FFI de la const struct rte_eth_rxconf * est donc *const ffi::RteEthRxConf , et non Option<*const ffi::RteEthRxConf> .