2015-08-27 5 views
2

У меня есть библиотека Rust (1.2), и я хочу использовать ее функции из Python (3.4), используя FFI Rust. Я на OSX 10.10 Йосемити.Как исправить ошибку сегментации при передаче массива int?

Почти все мои функции принимают изменяемую ссылку ломтика как вход:

pub fn myfunction<T>(array: &mut [T]) { ... } 

Я тогда разоблачить эту функцию, чтобы использовать вне ржавчины с:

#[no_mangle] 
pub extern fn ffi_myfunction(array_pointer: *const libc::int8_t, n: libc::size_t) { 
    assert!(!array_pointer.is_null()); 
    assert!(n != 0); 
    let mut to_sort = unsafe { 
     slice::from_raw_parts_mut(array_pointer as *mut i8, n as usize) 
    }; 
    myfunction(&mut to_sort); 
} 

Это прекрасно работает: с помощью языка Python модуль ctypes я могу назвать ffi_myfunction() с Numpy массива:

#!/usr/bin/env python3 

import ctypes 
import numpy as np 

rustlib = ctypes.CDLL("target/debug/libmylib.dylib") 

array = np.arange(5, dtype=np.int8) 

rustlib.ffi_myfunction(ctypes.c_void_p(array.ctypes.data), len(array)) 

У меня также есть ржавая реализация с libc::int16_t, libc::int32_t и libc::int64_t, и я могу назвать их np.int16, np.int32 и np.int64.

У меня есть второй набор функций Rust, которые я хочу вызвать из Python. Эти функции немного отличаются, поскольку они берут изменяемую ссылку на вектор (а не к ломтику):

pub fn myotherfunction<T>(array: &mut Vec<T>) { ... } 

Затем я создаю мою обертку, как например:

#[no_mangle] 
pub extern "C" fn ffi_myotherfunction(array_pointer: *const libc::int8_t, n: libc::size_t) { 
    assert!(!array_pointer.is_null()); 
    assert!(n != 0); 
    let mut to_sort = unsafe { 
     Vec::from_raw_parts(array_pointer as *mut i8, n as usize, n as usize) 
    }; 
    myotherfunction(&mut to_sort); 
} 

К сожалению, я получаю ошибку сегментации при вызов ffi_myotherfunction() из Python.

После некоторого исследования, я могу сказать следующее:

  1. Добавление println!() макроса в любом месте либо myotherfunction() или ffi_myotherfunction() сделать функцию, чтобы работать должным образом. Вывод будет таким, как ожидалось.
  2. Использована библиотека ржавчины segfaults для любого используемого целого размера (целые числа 8, 16, 32 и 64 бита).
  3. Segfault, похоже, не от myotherfunction(), а от звонка до Vec::from_raw_parts(). Например, я могу прокомментировать звонок myotherfunction() от ffi_myotherfunction(), оставив только небезопасный блок, и segfault все еще происходит.

Таким образом, существует разница между slice::from_raw_parts_mut() и Vec::from_raw_parts().

Но я не могу понять, что вызывает этот segfault. Я что-то упускаю? Я делаю что-то неправильно? Может ли быть проблема с тем, как numpy хранит свои данные? Или, может быть, что-то о жизни, заимствованиях или каких-либо других понятиях ржавчины, которые я не получаю?

Спасибо!

ответ

5

Вы должны использовать только Vec::from_raw_parts с данными, которые были выделены для кода Rust с помощью распределительных устройств Rust. Все остальное по-настоящему небезопасно.

Я ожидаю, что Python использует malloc, но Rust использует jemalloc. Если jemalloc поручено освободить адрес, который не был выделен jemalloc, он, я считаю, сбой. Таким образом, если вектор освобождается (то есть он выходит из области действия, его деструктор запускается) или если ему необходимо перераспределить (например,если вы нажмете на него элемент), вы столкнетесь с крахом.

Первая проблема заключается в том, что Vec имеет свой деструкторный запуск; это может быть изменено путем вызова std::mem::forget(to_sort), когда вы закончите с ним. Другая проблема, связанная с сбоем любого перераспределения, намного опаснее; вы в основном сделали это, что вы не можете безопасно получить доступ к своему вектору с изменчивостью и должны быть чрезвычайно осторожно во всем, что вы с ним делаете. Действительно, вы должны предположить, что все на Vec сделают сбой. Вместо этого вы должны использовать &mut [T], если то, что вы хотите, можно сделать с ним.

+0

Так что я должен использовать 'slice :: from_raw_parts_mut()' вместо 'Vec :: from_raw_parts()', это что? –

+0

@big_gie: действительно. –

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