Ciao Rust community,
I am currently fiddling around with the FFI of Rust. In fact, I need to call a few C functions of from the zlib C library. Right now I am focused on the compress
method:
ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen));
My C knowledge is very limited, which may be one of the reasons I am struggling with this.
The Rust code I wrote up until now, is as follows:
use crate::prelude::*;
use std::convert::From;
use std::os::raw::{c_int, c_ulong};
type Bytef = u8;
type uLongf = c_ulong;
type uLong = c_ulong;
#[link(name = "z", kind = "static")]
extern "C" {
fn compressBound(sourceLen: uLong) -> uLong;
fn compress(
dest: *mut Bytef,
destLen: *mut uLongf,
source: *const Bytef,
sourceLen: uLong,
) -> c_int;
fn uncompress(
dest: *mut Bytef,
destLen: *mut uLongf,
source: *const Bytef,
sourceLen: uLong,
) -> c_int;
}
pub struct Zipper;
impl Zipper {
pub fn compress(buffer: &Buffer) -> AlsResult<Buffer> {
let unzipped_data_len: uLong = buffer.data_len() as uLong;
if unzipped_data_len == 0 {
return Err(throw(
3,
AlsErrorKind::Unkown,
format!("Passed a Buffer with a data length of `0` to Zipper::compress"),
));
}
let zipped_data_buf_len: uLong;
unsafe {
// this call to zlib is successful
zipped_data_buf_len = compressBound(unzipped_data_len);
}
let mut buf = Buffer::new(zipped_data_buf_len as usize);
// Creating raw pointers for `compress()` here
let buf_ptr = buf.as_mut_ptr();
let raw_data = buffer.as_ptr();
unsafe {
// this crashes
let result = compress(
buf_ptr,
zipped_data_buf_len as *mut uLong,
raw_data,
unzipped_data_len,
);
match LibZCode::from(result) {
LibZCode::Ok => (),
any => {
return Err(throw(
0,
AlsErrorKind::Unkown,
format!("Error calling zlib::compress() = {:?}", any),
))
}
}
}
Ok(buf)
}
}
Buffer looks like this:
pub struct Buffer {
data: Vec<u8>,
capacity: usize,
data_len: usize,
}
cargo test
throws the following error for a unit test of Zipper::compress(buf)
:
process didn't exit successfully: `/path/libbase/target/debug/deps/libbase-4b4bb560900cabe5` (signal: 11, SIGSEGV: invalid memory reference)
Do I have to change the in-memory representation of the data field of the Buffer struct - if so, in which way? Buffer implements AsRef<[u8]>
and AsMut<[u8]>
, referring to Buffer.data. I tried to call the zlib compress function with two Vec<u8>
, but this didn't work either.
Is the mistake here on the Rust side, or do I have to check if I violate any contracts for the C pointers the compress()
function uses?
Best regards and stay healthy!