"invalid argument" calling sane_open in Rust through FFI - c

I'm trying to set up a Rust FFI for libsane, the Linux scanning library. Executing the sane_open function returns the error code 4 indicating an invalid argument. I believe it has something to do with my parameter declaration.
// If successful, places a new handle in *h
// SANE_String_Const is const char* and SANE_Handle is void*
SANE_Status sane_open(SANE_String_Const devname, SANE_Handle *h);
Bindgen generates the following:
pub type SANE_String_Const = *const ::std::os::raw::c_char
pub type SANE_Handle = *mut ::std::os::raw::c_void
pub fn sane_open(devname: SANE_String_Const, handle: *mut SANE_Handle) -> SANE_Status;
Here is what I have done:
pub fn test_open() {
unsafe {
let mut version_code = 0;
let result = sane_init(&mut version_code, None);
assert_eq!(result, SANE_Status_SANE_STATUS_GOOD);
let mut handle: SANE_Handle = std::ptr::null_mut();
let dev = CString::new("net1;dev0").unwrap();
let result = sane_open(dev.as_ptr(), &mut handle);
assert_eq!(result, SANE_Status_SANE_STATUS_GOOD);
sane_close(handle);
sane_exit();
}
}
Note that bindgen generates an Option<_> type for the callback where None means passing NULL. My minimal working example in C works flawlessly:
/* Link with -l sane */
#include <sane/sane.h>
#include <stdio.h>
#include <assert.h>
int main() {
SANE_Int version_code = 0;
assert(sane_init(&version_code, NULL) == SANE_STATUS_GOOD);
SANE_Handle h;
SANE_Status r = sane_open("net1;dev0", &h);
printf("Result: %d\n", r);
if(r == 0)
sane_close(h);
sane_exit();
}
What's wrong? Why does my Rust code behave differently?

Related

Why does calling a Rust library from C result in memory leakage?

I'm trying to prove that C can call a Rust library. It works, but when I monitor the memory usage of my program, it keeps on getting bigger and bigger.
Cargo.toml:
[lib]
name="test_ccallr"
crate-type=["cdylib"]
path = "src/lib.rs"
[dependencies]
libc = "0.2"
C code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
struct Payload_t{
char* data;
int len;
};
int show_str(char* raw, struct Payload_t *data);
int main()
{
while(1){
char * p_raw = "hlease print it !ello this is string from c, please print it !";
char * p_raw_ = "hhello this is another ";
char * pp = (char* )malloc(strlen(p_raw));
memcpy(pp, p_raw, strlen(p_raw));
struct Payload_t *tmp = (struct Payload_t*)malloc(sizeof (struct Payload_t));
struct Payload_t *_tmp = tmp;
tmp->data = (char*)malloc(strlen(p_raw_));
memcpy(tmp->data, p_raw_, strlen(p_raw_));
tmp->len = strlen(p_raw_);
printf("\n%d %d %d", pp, tmp, tmp->data);
show_str(pp, tmp);
printf("\n%d %d %d", pp, tmp, tmp->data);
free(pp);
free(tmp->data);
//free(_tmp);
usleep(5);
}
return 0;
}
I build my C code with the following command:
gcc main.c -L ./ -Bstatic -l:libtest_ccallr.so -o test[lib]
Rust code:
//use std::os::raw::{c_char, c_int};
extern crate libc;
use libc::{c_char, c_int};
use std::error::Error;
use std::ffi::CStr;
#[repr(C)]
pub struct Payload_t {
data: *const u8,
len: c_int,
}
#[no_mangle]
pub extern "C" fn show_str(raw: *const c_char, data: *const Payload_t) -> i32 {
let c_str: &CStr = unsafe { CStr::from_ptr(raw) };
if let Err(err) = c_str.to_str() {
eprintln!("{}", err.description());
return 0;
}
let str_from_ptr = c_str.to_str().unwrap();
let payload_ptr: Payload_t = unsafe { *Box::from_raw(data as *mut Payload_t) };
let payload = unsafe { std::slice::from_raw_parts(payload_ptr.data, payload_ptr.len as usize) };
println!("the raw string is {}", str_from_ptr);
println!(
"the length string is {}",
std::str::from_utf8(payload).unwrap()
);
return 0;
}
If I uncomment //free(_tmp);, the program will crash. If I keep this line commented, and run the program, it can run, but it leaks memory.
Is there anything that is not proper?
This is an inappropriate usage of Box::from_raw:
let payload_ptr: Payload_t = unsafe { *Box::from_raw(data as *mut Payload_t) };
From the documentation, emphasis mine (please read the documentation for unsafe functions):
After calling this function, the raw pointer is owned by the resulting Box. Specifically, the Box destructor will call the destructor of T and free the allocated memory. For this to be safe, the memory must have been allocated in accordance with the memory layout used by Box.
You should only use this function for data that was allocated by Box::new that you are retaking ownership of. Your case is neither. Box is deallocating the memory allocated by C. That's most likely what is causing your call to free to crash, as Rust has scribbled over the memory with it's own destructor.
A better way of writing your Rust function does not attempt to take ownership of data:
#[no_mangle]
pub unsafe extern "C" fn show_str(raw: *const c_char, data: *const Payload_t) -> i32 {
let c_str = CStr::from_ptr(raw);
let str_from_ptr = match c_str.to_str() {
Ok(s) => s,
Err(err) => {
eprintln!("{}", err);
return 0;
}
};
let payload_ptr = &*data;
let payload = std::slice::from_raw_parts(payload_ptr.data, payload_ptr.len as usize);
let s = match std::str::from_utf8(payload) {
Ok(s) => s,
Err(err) => {
eprintln!("{}", err);
return 0;
}
};
println!("the raw string is {}", str_from_ptr);
println!("the length string is {}", s);
0
}

Is it possible to access elements of a struct using pointers in Rust?

In C, we can access individual elements of a struct via pointers. How do we do the same in Rust?
The code below shows how to access elements using pointers in C.
#include <stdio.h>
#include <stdlib.h>
typedef struct __attribute__ ((packed)) {
int a;
int b;
int c;
} Data;
Data* new_data(const int a, const int b, const int c) {
Data* data = malloc(sizeof(Data));
data->a = a;
data->b = b;
data->c = c;
return data;
}
int main(int argc, char* argv[]) {
Data* data = new_data(23, 35, 12);
// accessing elements via pointers
printf("\n --- Using pointers ---\n");
printf("a: %d\n", *((int*)data + 0));
printf("b: %d\n", *((int*)data + 1));
printf("c: %d\n", *((int*)data + 2));
// using pointer magic
printf("\n --- Using pointer magic ---\n");
printf("b: %d\n", *((int*)((char*)data + sizeof(int))));
printf("c: %d\n", *((int*)((char*)data + sizeof(int) * 2)));
// accessing elements via name
printf("\n --- Using names ---\n");
printf("a: %d\n", data->a);
printf("b: %d\n", data->b);
printf("c: %d\n", data->c);
free(data);
return 0;
}
The above is compiled using gcc and I'm aware it's also platform specific, but it's not my concern.
The below is what I currently have in Rust.
struct Data<T> {
el: Vec<T>
}
impl <T> Data<T> where T: Copy {
fn new(a: T, b: T, c: T) -> Self {
let mut s = Self { el: Vec::with_capacity(3) };
s.el.push(a);
s.el.push(b);
s.el.push(c);
return s;
}
fn get_a(&self) -> T { self.el[0] }
fn get_b(&self) -> T { self.el[1] }
fn get_c(&self) -> T { self.el[2] }
}
fn main() {
let mut data = Data::new(23, 35, 12);
println!("data capacity: {:?}", data.el.capacity());
println!("a: {:?}", data.get_a());
println!("b: {:?}", data.get_b());
println!("c: {:?}", data.get_c());
}
I'd like to be able to use
struct Data<T> {
a: T,
b: T,
c: T
}
and access each element via their index.
In the general case, there is no way to do this correctly in Rust today. However, your particular struct avoids some of the worst problems, making it safe to borrow the entire struct as a borrowed slice (&[T]). To do so you need to do three things:
Mark the struct repr(C), but not repr(packed)! Packed structs are unaligned, and references must always be properly aligned.
Check that the size of the struct is no larger than isize::MAX.
Use slice::from_raw_parts to borrow a &[T] from the &Data<T>.
For a point-by-point justification of why this is sound, see Is it legal to cast a struct to an array?
#[repr(C)]
struct Data<T> {
pub a: T,
pub b: T,
pub c: T,
}
impl<T> Data<T>
where
T: Copy,
{
fn new(a: T, b: T, c: T) -> Self {
Data { a, b, c }
}
// N.B. you could also implement `AsRef<[T]>` and/or `Borrow<[T]>`, which
// are used frequently in generic code
fn as_slice(&self) -> &[T] {
assert!(std::mem::size_of::<Self>() <= isize::MAX as _);
// This `unsafe` block was copied from Stack Overflow without proving
// its use is correct in this context, so it's almost certainly wrong
unsafe { std::slice::from_raw_parts(self as *const _ as *const T, 3) }
}
}
Here's a test function to add confidence that casting to a slice works.
unsafe fn test_slice_data_equiv<T: Clone>(t: &T) {
let data = Data { a: t.clone(), b: t.clone(), c: t.clone() };
let slice: [T; 3] = [ t.clone(), t.clone(), t.clone()];
fn as_u8_ptr<U>(r: &U) -> * const u8 {
r as * const U as * const u8
}
let data_ptr = as_u8_ptr(&data);
let slice_ptr = as_u8_ptr(&slice);
assert_eq!(as_u8_ptr(&data.a).offset_from(data_ptr),
as_u8_ptr(&slice[0]).offset_from(slice_ptr),
"Data.a != slice[0]");
assert_eq!(as_u8_ptr(&data.b).offset_from(data_ptr),
as_u8_ptr(&slice[1]).offset_from(slice_ptr),
"Data.b != slice[1]");
assert_eq!(as_u8_ptr(&data.c).offset_from(data_ptr),
as_u8_ptr(&slice[2]).offset_from(slice_ptr),
"Data.c != slice[2]");
}
#[test]
fn test_some_offsets() {
unsafe {
test_slice_data_equiv(&0_u32);
test_slice_data_equiv(&0_u64);
}
}

Calling Rust from Swift

On the Rust side I wrote a function that returns a String as a pointer of bytes (laid out in memory as a C struct):
#[repr(C)]
pub struct RustByteSlice {
pub bytes: *const u8,
pub len: size_t,
}
#[no_mangle]
pub extern "C" fn get_string_from_rust() -> RustByteSlice {
let s = "This is a string from Rust.";
RustByteSlice {
bytes: s.as_ptr(),
len: s.len() as size_t,
}
}
When generating a header file for it using cbindgen it gives me the following output:
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct {
const uint8_t *bytes;
size_t len;
} RustByteSlice;
RustByteSlice get_string_from_rust(void);
char *hello(const char *to);
void hello_release(char *s);
void utf8_bytes_to_rust(const uint8_t *bytes, size_t len);
In my Xcode project, this header is used as the bridging header, and the shared library compiled from the rust code is added to the dependency list. The header and include folders are defined in the build properties.
On the swift side I'm calling the rust function the following way:
struct RustByteSlice {
var bytes: UnsafePointer<UInt8>
var len: Int
func asUnsafeBufferPointer() -> UnsafeBufferPointer<UInt8> {
return UnsafeBufferPointer(start: bytes, count: len)
}
func asString(encoding: String.Encoding = String.Encoding.utf8) -> String? {
return String(bytes: asUnsafeBufferPointer(), encoding: encoding)
}
}
func strPtrRet() {
let rustString: RustByteSlice = get_string_from_rust()
if let stringFromRust = rustString.asString() {
print("got a string from Rust: (stringFromRust)")
} else {
print("Could not parse Rust string as UTF-8")
}
}
On the line let rustString: RustByteSlice = get_string_from_rust(), I get the following error:
Cannot convert value of type '__ObjC.RustByteSlice' to specified type 'ed25_ios_app.RustByteSlice'
How can I solve or work around this error ?
After working through your code, you are redefining RustByteSlice.
From Using Imported C Structs and Unions in Swift, you don't need to redefine it as it automatically imports the struct.
The below swift code works.
func strPtrRet() -> String? {
let rustString: RustByteSlice = get_string_from_rust()
let buffer = UnsafeBufferPointer(start: rustString.bytes, count: rustString.len)
let string = String(bytes: buffer, encoding: String.Encoding.utf8)
if let stringFromRust = string {
print("got a string from Rust: (stringFromRust)")
} else {
print("Could not parse Rust string as UTF-8")
}
return string
}

swift3.0 Cannot convert value of type '[UnsafeMutablePointer<Int8>]' to expected argument type 'UnsafeMutablePointer<Int8>?'

This code worked well in Swift2.3 and now I am converting it to Swift3. So I am getting this error. Anyone has idea, how to fix this?
var cmdLnConf: OpaquePointer?
fileprivate var cArgs: [UnsafeMutablePointer<Int8>]
public init?(args: (String,String)...) {
// Create [UnsafeMutablePointer<Int8>].
cArgs = args.flatMap { (name, value) -> [UnsafeMutablePointer<Int8>] in
//strdup move the strings to the heap and return a UnsageMutablePointer<Int8>
return [strdup(name),strdup(value)]
}
cmdLnConf = cmd_ln_parse_r(nil, ps_args(), CInt(cArgs.count), &cArgs, STrue)
if cmdLnConf == nil {
return nil
}
}
enter image description here
based on our discussion it seems that parameter in your C function should be char *p[]
I made a small test
//
// f.h
// test001
//
#ifndef f_h
#define f_h
#include <stdio.h>
void f(char *p[], int len);
#endif /* f_h */
I defined the function with some basic functionality
//
// f.c
// test001
#include "f.h"
void f(char *p[], int len) {
for(int i = 0; i<len; i++) {
printf("%s\n", p[i]);
};
};
with the required bridging header
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#include "f.h"
and swift 'command line' application
//
// main.swift
// test001
//
import Darwin
var s0 = strdup("alfa")
var s1 = strdup("beta")
var s2 = strdup("gama")
var s3 = strdup("delta")
var arr = [s0,s1,s2,s3]
let ac = Int32(arr.count)
arr.withUnsafeMutableBytes { (p) -> () in
let pp = p.baseAddress?.assumingMemoryBound(to: UnsafeMutablePointer<Int8>?.self)
f(pp, ac)
}
it finally prints
alfa
beta
gama
delta
Program ended with exit code: 0
based on the result, your have to use
let count = CInt(cArgs.count)
cArgs.withUnsafeMutableBytes { (p) -> () in
let pp = p.baseAddress?.assumingMemoryBound(to: UnsafeMutablePointer<Int8>?.self)
cmdLnConf = cmd_ln_parse_r(nil, ps_args(), count, pp, STrue)
}
WARNING!!!
don't call cArgs.count inside the closure, where the pointer is defined!

Swift2 #convention(c) with char* and type**

I am trying to write pointers to c method as such:
//c signature:
typedef void (*startDocumentSAXFunc) (void *ctx);
//Swift2 working code
let startDocument: #convention(c) (UnsafeMutablePointer<Void>) -> Void = { (ctx) -> Void in
NSLog("Start Document")
}
I can't find what type to use for xmlChar**
//c signature
typedef void (*startElementSAXFunc) (void *ctx,
const xmlChar *name,
const xmlChar **atts);
//Swift2 code
let startElement: #convention(c) (UnsafeMutablePointer, UnsafePointer, ???) -> Void = { (ctx, name, attributes) -> Void in
NSLog("Start Element \(name), \(attributes)")
}
I can't find what type to use for const char*
//c signature
typedef void (XMLCDECL *errorSAXFunc) (void *ctx,
const char *msg, ...);
//Swift2
let error: #convention(c) (UnsafeMutablePointer, ???) -> Void =
{ (ctx, msg) -> Void in
NSLog("Error \(msg)")
}
I tried the type UnsafePointer<CChar> but it is not working.
The aim here is to be able to use the libXML which is quicker than NSXML lib.
Thanks for your help !
The C function type
void (*startElementSAXFunc) (void *ctx,
const xmlChar *name,
const xmlChar **atts);
maps to Swift as
(UnsafeMutablePointer<Void>, UnsafePointer<xmlChar>, UnsafeMutablePointer<UnsafePointer<xmlChar>>) -> Void
so a valid startElementSAXFunc is
func onStartElement(ctx: UnsafeMutablePointer<Void>,
name: UnsafePointer<xmlChar>,
atts: UnsafeMutablePointer<UnsafePointer<xmlChar>>) {
// ...
}
and that can be assigned to the handler without any cast:
var handler = xmlSAXHandler()
handler.initialized = XML_SAX2_MAGIC
// ...
handler.startElement = onStartElement
Now xmlChar is a type alias for unsigned char which is UInt8
in Swift, and different from CChar aka Int8, therefore an
additional cast is necessary if you convert the passed characters
to a Swift string in onStartElement:
let sName = String.fromCString(UnsafePointer(name))!
print("start element, name = ", sName)
atts is a pointer to an array of character pointers, and you
can traverse that array quite similar as you would in C:
if atts != nil {
var ptr = atts
while ptr[0] != nil && ptr[1] != nil {
let key = String.fromCString(UnsafePointer(ptr[0]))!
let value = String.fromCString(UnsafePointer(ptr[1]))!
print("attr:", key, "=", value)
ptr += 2
}
}
In a similar fashion, you can implement the endElementSAXFunc
and charactersSAXFunc.
With the errorSAXFunc however, there is a big problem:
that function uses a variable argument list and therefore cannot
be implemented in Swift, so you are out of luck here.
The following compiles and seems to run:
let onError : #convention(c) (UnsafeMutablePointer<Void>, UnsafePointer<xmlChar>)->Void = {
(ctx, msg) in
let sMsg = String.fromCString(UnsafePointer(msg))!
print("error:", sMsg)
}
handler.error = unsafeBitCast(onError, errorSAXFunc.self)
but that is – to the best of my knowledge – undefined behaviour.
It is also not helpful because you will get the error format string
only (which was just %s in my test case).
check this 'self explanatory' example
let str = "A"
var c = str.utf8.map { (c) -> CChar in
return CChar(c)
}[0]
print(c, c.dynamicType) // 65 Int8
var p = UnsafeMutablePointer<CChar>.alloc(1)
print(p.memory, p.memory.dynamicType) // 0 Int8
p.memory = 65
func modify(pp: UnsafeMutablePointer<UnsafeMutablePointer<CChar>>)->Void {
print(pp.memory.memory, pp.memory.memory.dynamicType)
}
let pp = withUnsafeMutablePointer(&p){ $0 }
print(pp, pp.dynamicType) // 0x0000000119bbf750 UnsafeMutablePointer<UnsafeMutablePointer<Int8>>
modify(pp) // 65 Int8
...
p.dealloc(1)
modify(pp) // -107 Int8
// -107 is some 'random' value, becase the memory there was dealocated!!
UnsafePoiner<CChar> is const char * while
UndafeMutablePointer<CChar> is char *
etc ...

Resources