Reputation: 7561
As an exercise, I'm attempting to write a GraphicsMagick FFI wrapper in Rust. I'm having an issue replicating some reference C code:
Image
*image = (Image *) NULL;
ImageInfo
*imageInfo;
ExceptionInfo
exception;
InitializeMagick(NULL);
imageInfo=CloneImageInfo(0);
GetExceptionInfo(&exception);
And here is my (naive) translation to Rust:
let img: *mut ffi::Image;
let img_info: *mut ffi::ImageInfo;
let exception: *mut ffi::ExceptionInfo = ptr::null_mut();
unsafe {
ffi::InitializeMagick(ptr::null_mut());
img_info =
ffi::CloneImageInfo(ptr::null_mut() as *const ffi::ImageInfo);
ffi::GetExceptionInfo(exception);
// ...
}
This compiles just fine, but when I try to run it, I see:
magick/error.c:388: GetExceptionInfo: Assertion `exception != (ExceptionInfo *) ((void *)0)' failed
which is caused by ffi::GetExceptionInfo(exception)
. The only difference seems to be that the C exception isn't "initialized", but I don't know enough about C to know if there is a difference between a null and an empty/uninitialized pointer.
Upvotes: 1
Views: 180
Reputation: 12547
The difference between your C and Rust code is that the C version allocates an ExceptionInfo
instance on the stack and passes into the GetExceptionInfo
a pointer referencing that instance.
Your Rust code, on the other hand, passes a NULL
pointer.
GetExceptionInfo
specifically guards against being passed a NULL
pointer, you can see the assertion's code here, in magick/error.c.
I don't know what kind of FFI bindings you use, but if the ExceptionInfo
is fully defined in them then you should be able to allocate it on the stack and pass a reference to it just like in the C version:
let mut exception: ffi::ExceptionInfo = unsafe {std::mem::uninitialized()};
unsafe {ffi::GetExceptionInfo (&mut exception);}
Upvotes: 4
Reputation: 430673
The error message states (rewritten a bit):
Assertion
exception != NULL
failed
That is, you cannot pass NULL to that method. Note the C code:
ExceptionInfo exception;
This is not a pointer. You need to allocate space for it and then pass in a reference to the allocated space.
The documentation shows the definition:
typedef struct _ExceptionInfo
{
char
*reason,
*description;
ExceptionType
severity;
unsigned long
signature;
} ExceptionInfo;
You will need to represent this in Rust. Something like this untested code:
extern crate libc;
#[repr(C)]
struct ExceptionInfo {
reason: *const libc::c_char,
description: *const libc::c_char,
severity: ExceptionType,
signature: libc::c_ulong,
}
#[repr(C)]
enum ExceptionType {
UndefinedException,
WarningException = 300,
// the rest
}
Then you need to allocate it and pass a reference. More untested code:
let img_info;
let mut exception = ffi::ExceptionInfo::new();
unsafe {
ffi::InitializeMagick(ptr::null_mut());
img_info =
ffi::CloneImageInfo(ptr::null_mut() as *const ffi::ImageInfo);
ffi::GetExceptionInfo(&mut exception);
// ...
}
Note that Rust style is 4 space indents.
Upvotes: 4