Как можно передать указатель между Rust и Python?

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

Полные примеры кода и отчет о сбое: https://gist.github.com/robyoung/3644f13a05c95cb1b947

Код

#![feature(libc)]
#![feature(alloc)]
extern crate libc;
use std::boxed;

pub struct Point {
    x: i64,
    y: i32,
}

#[no_mangle]
pub extern "C" fn start_state() -> *mut Point {
    let point = Box::new(Point{x: 0, y: 10});
    let raw = unsafe { boxed::into_raw(point) };
    println!("{:?}", raw);
    raw
}

#[no_mangle]
pub extern "C" fn continue_state(point: *mut Point) -> i32 {
    println!("{:?}", point);
    let p = unsafe { Box::from_raw(point) };
    println!("{} {}", p.x, p.y);
    0
}
import ctypes

lib = ctypes.cdll.LoadLibrary('target/libpytesttype.so')
lib.start_state.restype = ctypes.c_void_p

pointer = lib.start_state()
print("{:x}".format(pointer))
lib.continue_state(pointer)

Выход

0xdc24000
10dc24000
0xdc24000
[1]    64006 segmentation fault  python src/main.py

Что я делаю неправильно?

Ответ 1

eryksun прибил его:

На стороне Python вам не хватает lib.continue_state.argtypes = (ctypes.c_void_p,). Не определяя параметр как указатель, ctypes использует преобразование по умолчанию для целого числа Python, которое усекает значение до 32-битного, например. 0x0dc24000. Если вам посчастливится получить доступ к этому адресу, немедленно вызовите segfault.

Мой вывод (с моим собственным дополнением) был:

0x103424000
  103424000
0x  3424000

Итак, форматер Debug для указателей должен быть точным. Не знаете, почему ваш выход отличается.

После добавления

lib.continue_state.argtypes = (ctypes.c_void_p,)

Программа прошла нормально.