2016-08-30 16 views
1

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面?

+0

どのように2つのプログラムを実行しますか?別々に実行するか、または別のものから実行しますか? – monkeyStix

+1

'CString :: new(" MBUF_POOL ")。unwrap()。as_ptr()'は危険です。あなたは、これから得られる生のポインタが十分に有効であると確信していますか? TBH、この 'CString'がいつドロップされるのかは分かりません。 'dpdk_rte_pktmbuf_pool_create'への関数呼び出しの前に*ドロップされた場合、ポインタは無効になります。本当に安全ではないFFI関数の 'dpdk_rte_pktmbuf_pool_create'のような"安全な "ラッパーを書くのは本当に避けなければなりません! – sellibitze

答えて

3

CString::new("…").unwrap().as_ptr()は機能しません。CStringは一時的なものなので、as_ptr()呼び出しは、その一時的なポインタを使用したときにおそらくぶら下がります。これは、あなたがポインタを使用しない限り、Rustの定義による "安全"ですが、最終的にはunsafeブロックで行います。文字列を変数にバインドし、その変数にas_ptrを使用する必要があります。

これはよくある問題です。a proposal to fix the CStr{,ing} API to avoid itもあります。

さらに、生ポインタはヌル可能であるため、const struct rte_eth_rxconf *のRust FFIは、ではなく*const ffi::RteEthRxConfになります。

+2

もしこのことについて人々に警告するために[その機能**の巨大な警告ブロック**](https://doc.rust-lang.org/std/ffi/struct.CStr.html#method.as_ptr)しかなければ... – Shepmaster

+2

とにかくそれをするとき、[それについて警告できるツール](https://github.com/Manishearth/rust-clippy/wiki#temporary_cstring_as_ptr) (免責事項:私はClippy devのだ)の情報のため – mcarton

+0

おかげで、私はこのように見えるためにそれを変更した - '名= CStringのを聞かせて::新( "MBUF_POOL")(アンラップ);' '。 (u32、250、0、2176、dpdk :: rte_eal :: dpdk_rte_socket_id()); として、mb = dpdk :: rte_mbuf :: dpdk_rte_pktmbuf_pool_create(name.as_ptr()、 (8191 * nb_ports)それでも同じ振る舞いをしています。私は、 "MBUF_POOL"文字列を含む構造体へのポインタを渡そうとしますが、C側でNULLが判明します。 – kentonspr

関連する問題