2016-08-30 5 views
1

Я пытаюсь получить необработанный указатель из функции C в ржавчине и использовать тот же необработанный указатель, что и аргумент в другой функции C из другой библиотеки. Когда я передаю исходный указатель, я получаю указатель NULL на стороне C.Необработанный указатель превращается в нуль, переходящий из Rust в C

Я попытался сделать упрощенную версию моего вопроса, но когда я делаю это работает, как я бы ожидать, что это -

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

Rust код -

#[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 для отладки, я могу видеть, что я передаю указатель на стороне ржавчины, но я вижу, что NULL на стороне C -

(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 мб имеет адрес и передается. В кадре 0 функция приема в библиотеке показывает ее как 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 на С стороны?

+0

как вы управляете двумя программами? отдельно, или вы запускаете один из другого? – monkeyStix

+1

'CString :: new (" MBUF_POOL "). Unwrap(). As_ptr()' выглядит опасным. Вы уверены, что необработанный указатель, который вы получаете от этого, достаточно долго? TBH, я не знаю, когда именно этот «CString» отбрасывается. Если он отбрасывается * до *, вызов функции на 'dpdk_rte_pktmbuf_pool_create', указатель будет недействительным. Вам действительно следует избегать написания «безопасных» оберток, таких как 'dpdk_rte_pktmbuf_pool_create' для функций FFI, которые не очень безопасны! – 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.

Кроме того, необработанный указатель обнуляется сам по себе, поэтому эквивалент RFI FFI const struct rte_eth_rxconf * будет *const ffi::RteEthRxConf, а не Option<*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") разворачивать();' ' . пусть Мб = dpdk :: rte_mbuf :: dpdk_rte_pktmbuf_pool_create (name.as_ptr(), (8191 * nb_ports) как u32, 250, 0, 2176, dpdk :: rte_eal :: dpdk_rte_socket_id()); ' Однако, I» m все еще получает такое же поведение. Я пытаюсь передать указатель на структуру, содержащую строку «MBUF_POOL», но она оказывается NULL на стороне C. – kentonspr

Смежные вопросы