My Rust test code
extern "C" {
fn test_int_only(n : libc::c_int);
fn test_int_and_str(s : CString , n : libc::c_int);
}
pub fn test1() {
unsafe {
test_int_only(0);
test_int_only(1);
test_int_only(2);
test_int_only(4);
test_int_only(-12);
}
}
pub fn test2() {
unsafe {
test_int_and_str(CString::new("Foo").unwrap(),0);
test_int_and_str(CString::new("Bar").unwrap(),1);
test_int_and_str(CString::new("Baz").unwrap(),2);
test_int_and_str(CString::new("Fub").unwrap(),4);
test_int_and_str(CString::new("Bub").unwrap(),-12);
}
}
My C code
void test_int_only(int abc){
printf("%d\n", abc);
}
void test_int_and_str(const char* name,int abc) {
printf("%s %d\n", name, abc);
}
When testing for test_int_only()
1
2
4
-12
When testing for test_int_and_str()
Foo 4
Bar 4
Baz 4
Fub 4
Bub 4
It seems that the 2nd arg is being interpreted (either in rust or c) as sizeof string, rather than the value passed from the Rust code. I'm guessing it's related to either a calling convention or null termination not working correctly. It's a C dll, with _cdecl (windows 32bit dll) calling convention. Interestingly, passing a (opaque) pointer and an int (in another test) works fine so I don't think it's a calling convention issue.
Correct. You are experiencing undefined behavior here.
Your C-Function has a different signature from the extern function you declared in Rust-Code. First of all, passing types that are not
#[repr(C)]
to an extern function is undefined behavior and there used to be a lint for that afaik. Second, aCString
is not achar*
, it is a struct with internal data. If you want to pass aconst char*
, you have to pass a*const u8
. You can get such a pointer from aCString
through theinto_ptr
function.Note that
into_ptr
leaks the memory, you need to usefrom_ptr
again to get aCString
object that can get deallocated. If you just want to lend out theCString
object you can do something along the following lines: