Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a pointer be passed between Rust and Python?

I am experimenting with writing a library in Rust that I can call from Python code. I would like to be able to pass a void pointer back to Python so that I can hold state between calls into Rust. However, I get a segfault in Rust when trying to access the pointer again.

Full code samples and crash report: https://gist.github.com/robyoung/3644f13a05c95cb1b947

The code

#![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)

The output

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

What am I doing wrong?

like image 639
Rob Young Avatar asked May 08 '15 21:05

Rob Young


1 Answers

eryksun nailed it:

On the Python side, you're missing lib.continue_state.argtypes = (ctypes.c_void_p,). Without defining the parameter as a pointer, ctypes uses the default conversion for a Python integer, which truncates the value to 32-bit, e.g. 0x0dc24000. If you're lucky accessing that address triggers a segfault immediately.

My output (with my own padding) was:

0x103424000
  103424000
0x  3424000

So the Debug formatter for pointers should be fine. Not sure why your output differs.

After adding

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

The program ran just fine.

like image 50
3 revs Avatar answered Nov 14 '22 12:11

3 revs