C関数のrawポインタをrustで取得しようとしていて、同じrawポインタを別のライブラリの別のC関数の引数として使用しようとしています。生のポインタを渡すと、私はC側にNULLポインタで終わります。RawポインタがRustから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);
}
錆コード -
#[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の出力が得られます。
~/Dev/rust_test$ sudo ./target/debug/rust_test
Value - 0
~/Dev/rust_test$
しかし、これをDPDKライブラリに対して実行しようとすると、同じ方法でローポインタを取得して渡しますが、segfaultを取得します。私はデバッグにGDBを使用している場合は、私は錆側のポインタを渡していることを確認することができますが、私はそれがC側のNULL参照 -
フレーム1では(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,
、メガバイトアドレスを持ち、通過しています。フレーム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());
これは、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;
}
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);
私はポインタを渡すと、上記の私の単純化されたバージョンと同じように見えます。
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);
マイ変数
メガバイトは、私は別の関数に渡す生のポインタが含まれています
私は長さについてお詫びしますが、私は何か簡単なものを見逃しているように感じ、それを理解することができませんでした。私が渡されている各フィールドの構造体のアラインメントをチェックしましたし、私も私が期待するとして受信されるポインタの値を参照してください -
(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}
なぜポインタが上NULLに回っている上の任意のアイデアC面?
どのように2つのプログラムを実行しますか?別々に実行するか、または別のものから実行しますか? – monkeyStix
'CString :: new(" MBUF_POOL ")。unwrap()。as_ptr()'は危険です。あなたは、これから得られる生のポインタが十分に有効であると確信していますか? TBH、この 'CString'がいつドロップされるのかは分かりません。 'dpdk_rte_pktmbuf_pool_create'への関数呼び出しの前に*ドロップされた場合、ポインタは無効になります。本当に安全ではないFFI関数の 'dpdk_rte_pktmbuf_pool_create'のような"安全な "ラッパーを書くのは本当に避けなければなりません! – sellibitze