How to publish a constant string in the Rust FFI? - rust

I want to have a Rust library expose a const char * static string to C, to be compatible with an existing interface (specifically librsync). That is, the C header file has
extern char const *my_string;
In C, the library would simply have
char const *my_string = "hi";
In Rust I've tried something like
pub static my_string: *const libc::c_char = unsafe { "hi\0" as *const libc::c_char };
but this complains
error: casting `&'static str` as `*const i8` is invalid
It seems like I can't use CString etc because they won't be a compile-time constant expression.

We need a public, static, unmangled pointer to some zero-terminated bytes:
#[export_name = "CONST_C_STR"] // or #[no_mangle]
pub static CONST_C_STR: &[u8; 20] = b"a constant c string\0";
This worked with a simple C program:
#include <stdio.h>
extern char * CONST_C_STR;
int main(int argc, char *argv[]) {
printf("%s\n", CONST_C_STR);
}

The crate c_str_macro provides a convenience macro c_str!, which appends a 0 byte to a Rust string literal and presents it as a CStr reference.
Disclaimer: I'm the author of the crate.

Related

Strange struct definition from crate nix

I just encountered this weird struct definition, it is in fcntl.rs from the crate nix.
pub struct OFlag: c_int {
/// Mask for the access mode of the file.
O_ACCMODE;
// other fields are omitted.
}
A normal struct in my perspective will be something like this:
struct Person{
name: String,
age: u8,
}
So, here are my doubts:
what is OFlag: c_int?
c_int is an type alias of i32. pub type c_int = i32;
Why don't its fields have any type annotation?
My surmise is that OFlag is of type c_int, and the fields are something similar to enum's fields.(compliant to the open syscall function signature int open(const char *pathname, int flags, mode_t mode) ) But this is just my guesswork, an explanation citing rust official doc would be appreciated.
The code you quoted is not valid Rust code on its own. It's code that gets passed to an internal macro of the nix crate called libc_bitflags!(). This macro takes the quoted code as input and transforms it into valid Rust code.
The libc_bitflags!() macro is a simple wrapper around the bitflags!() macro from the bitflags crate. The wrapper simplifies creating bitflags structs that take all their values from constants defined in the libc crate. For example this invocation
libc_bitflags!{
pub struct ProtFlags: libc::c_int {
PROT_NONE;
PROT_READ;
PROT_WRITE;
PROT_EXEC;
}
}
gets expanded to
bitflags!{
pub struct ProtFlags: libc::c_int {
const PROT_NONE = libc::PROT_NONE;
const PROT_READ = libc::PROT_READ;
const PROT_WRITE = libc::PROT_WRITE;
const PROT_EXEC = libc::PROT_EXEC;
}
}
which in turn will be expanded to Rust code by the bitflags!() macro. The libc::c_int type is used as the type of the bits field of the resulting struct. The constants inside will become associated constants of the resulting struct. See the documentation of the bitflags crate for further details.
If you look at the file you can see that the code inside the macro libc_bitflags!. The definition of the macro is here. There you can see that the macro ::bitflags::bitflags! is called and that libc_bitflags almost redirects the full input to bitflags. You can read more about that crate here.
Now to your questions:
OFlag will be after macro expansion a struct with a single attribute which is of type c_int:
pub struct OFlag {
bits: c_int,
}
The fields don't need a type because they won't exist anymore in the expanded code (after the macro was run). The bits are of the "type of the struct" so in your case c_int. The fields will be converted to associated constants:
impl OFlag {
pub const O_ACCMODE = Self { bits: libc::O_ACCMODE };
}
You can create an expansion of an example in the playground (Tools -> Expand macros)

How do I get an out string parameter from C using Rust's FFI?

I've been diving into FFI with Rust, and while there are some useful posts and documentation on passing in strings and sometimes getting a string back as the return value from a C function, I don't see any way to get an out parameter. To get my feet wet, I am trying to access a C library that exposes a function that is declared as:
unsigned char *some_func(
const unsigned char *key,
unsigned int klen,
const unsigned char *src,
unsigned char *dest,
unsigned int slen);
I think it should be declared roughly as:
use libc;
extern "C" {
fn some_func(
key: *const libc::c_uchar,
klen: libc::c_uint,
src: *const libc::c_uchar,
dest: *mut libc::c_uchar,
slen: libc::c_uint) -> *mut libc::c_uchar;
}
// wrapper
pub fn wrapped_func(key: &str, src: &str) -> String {
unsafe {
let key_len = key.len() as u32;
let key = std::ffi::CString::new(key).unwrap();
let src_len = src.len() as u32;
let src = std::ffi::CString::new(src).unwrap();
let key_ptr = key.as_ptr();
let src_ptr = src.as_ptr();
let mut dest: *mut std::ffi::CStr;
let result = PC1(key_ptr, key_len, src_ptr, &mut dest, src_len);
// ^^^^^^^^^ expected `u8`, found *-ptr
key_ptr = ptr::null();
src_ptr = ptr::null();
let result_string = if let Ok(s) = result.to_str() {
String::from(s)
} else {
String::new()
};
dest = ptr::null();
result_string
}
There are a few issues I'm having with this:
I don't know how to properly declare dest as my out string. What's the right way to get an output string? From Wrapping Unsafe C Libraries in Rust, it looks like I need to treat this as a CStr:
For cases where you’re getting a const char * from a C function and want to convert it to something Rust can use, you’ll need to ensure it’s not null, then convert it into a &CStr with an appropriate lifetime. If you can’t figure out how to express an appropriate lifetime, the safest thing is to immediately convert it into an owned String!
The C code - and therefore my extern function - declares the strings as unsigned char *, but when I try to invoke, I have a type mismatch between u8 and i8. Is it acceptable to just switch the extern to be c_char, or is this dangerous?
Is setting key_ptr = ptr::null() the correct way (and all that's needed) to release the memory safely?

static struct with C strings for lv2 plugin [duplicate]

This question already has answers here:
Creating a static C struct containing strings
(3 answers)
Closed 7 years ago.
I'm trying to learn Rust (newbie in low level programming), and want to translate a tiny lv2 amplifier (audio) plugin "amp.c" (C-code) from C to Rust. I actually got it working (here), but when the host terminates, valgrind says that "
64 bytes in 1 blocks are definitely lost". I think I know why this happens, but I don't know how to fix it.
Before you get tired of reading, here is the final question:
How do I statically allocate a struct that contains a C string?
And here is the introduction:
Why it happens (I think):
Host loads the library and calls lv2_descriptor()
const LV2_Descriptor*
lv2_descriptor()
{
return &descriptor;
}
which returns a pointer to a STATICALLY allocated struct of type LV2_Descriptor,
static const LV2_Descriptor descriptor = {
AMP_URI,
...
};
which is defined as
typedef struct _LV2_Descriptor {
const char * URI;
...
} LV2_Descriptor;
Why is it statically allocated? In the amp.c it says:
It is best to define descriptors statically to avoid leaking memory
and non-portable shared library constructors and destructors to clean
up properly.
However, I translated lv2_descriptor() to Rust as:
#[no_mangle]
pub extern fn lv2_descriptor(index:i32) -> *const LV2Descriptor {
let s = "http://example.org/eg-amp_rust";
let cstr = CString::new(s).unwrap();
let ptr = cstr.as_ptr();
mem::forget(cstr);
let mybox = Box::new(LV2Descriptor{amp_uri: ptr}, ...);
let bxptr = &*mybox as *const LV2Descriptor;
mem::forget(mybox);
return bxptr
}
So it's not statically allocated and I never free it, that's I guess why valgrind complains?
How am I trying to solve it?
I'm trying to do the same thing in Rust as the C-code does, i.e. statically allocate the struct (outside of lv2_descriptor()). The goal is to be fully compatible to the lv2 library, i.e "...to avoid leaking memory..." etc., as it says in the quote, right? So I tried something like:
static ptr1: *const u8 = (b"example.org/eg-amp_rust\n\0").as_ptr();
static ptr2: *const libc::c_char = ptr1 as *const libc::c_char;
static desc: LV2Descriptor = LV2Descriptor{amp_uri: ptr2, ...};
But this does not compile, there are error messages like
src/lib.rs:184:26: 184:72 error: the trait `core::marker::Sync` is not implemented for the type `*const u8` [E0277]
src/lib.rs:184 static ptr1: *const u8 = b"http://example.org/eg-amp_rust\n\0".as_ptr();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/lib.rs:184:26: 184:72 note: `*const u8` cannot be shared between threads safely
src/lib.rs:184 static ptr1: *const u8 = b"http://example.org/eg-amp_rust\n\0".as_ptr();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/lib.rs:184:26: 184:72 error: static contains unimplemented expression type [E0019]
src/lib.rs:184 static ptr1: *const u8 = b"http://example.org/eg-amp_rust\n\0".as_ptr();
Specific problem/question:
How do I statically allocate a struct that contains a C string?
The short answer is, you don't for now. Future Rust will probably gain this ability.
What you can do, is statically allocate a struct that contains null pointers, and set those null pointers to something useful when you call the function. Rust has static mut. It requires unsafe code, is not threadsafe at all and is (to the best of my knowledge) considered a code smell.
Right here I consider it a workaround to the fact that there is no way to turn a &[T] into a *const T in a static.
static S: &'static [u8] = b"http://example.org/eg-amp_rust\n\0";
static mut desc: LV2Descriptor = LV2Descriptor {
amp_uri: 0 as *const libc::c_char, // ptr::null() isn't const fn (yet)
};
#[no_mangle]
pub extern fn lv2_descriptor(index: i32) -> *const LV2Descriptor {
let ptr = S.as_ptr() as *const libc::c_char;
unsafe {
desc.amp_uri = ptr;
&desc as *const LV2Descriptor
}
}

Fitting string literals for different string classes

The problem
I am implementing a class where I want to let the user choose the string type (std::string, std::wstring, std::u16string, ...) via a template parameter. I currently fail to make the string literals fit the chosen string type: Once I decide for a literal prefix ("hello" vs. L"hello" vs. u"hello" vs. U"hello"), I get compilation errors for all incompatible string classes.
Toy example
As an example, consider the following code (compile with --std=c++11):
#include <string>
template<typename StringType>
void hello_string()
{
StringType result("hello");
}
int main()
{
// works
hello_string<std::string>();
hello_string<std::basic_string<char>>();
// the code below does not compile
hello_string<std::wstring>();
hello_string<std::basic_string<unsigned char>>();
hello_string<std::u16string>();
}
Function hello_string() shows the essence of what I want to do: have a string type as template parameter, and assign string literals to variables of this type.
Possible workaround
One way to overcome my problem would be to implement several specializations of the hello_string() function. The problem is that this would lead to several copies of each string literal - one for each string literal prefix. I think this is rather ugly, and there must be better way.
Another way could be to chose "normal" string literals as default values and have functions do a conversion to the different string types. While this would avoid code duplication, it would introduce unnecessary conversions of something that is actually constant.
You can make yourself a macro. First define a struct that wraps the char-choosing:
namespace details {
template<typename T>
struct templ_text;
template<>
struct templ_text <char>
{
typedef char char_type;
static const char_type * choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return narrow; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return narrow; }
};
template<>
struct templ_text < wchar_t >
{
typedef wchar_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return wide; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return wide; }
};
template<>
struct templ_text < char16_t >
{
typedef char16_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return u16; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return u16; }
};
template<>
struct templ_text < char32_t >
{
typedef char32_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return u32; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return u32; }
};
}
Wrap it into a nice macro:
#define TEMPL_TEXT(Ch, txt) details::templ_text<Ch>::choose(txt, L##txt, u##txt, U##txt)
Then your function would be:
template<typename StringType>
void hello_string()
{
StringType result(TEMPL_TEXT(typename StringType::value_type, "Hello"));
}
I think that unused copies of the string will be optimized away.

C library freeing a pointer coming from Rust

I want to do Rust bindings to a C library which requires a callback, and this callback must return a C-style char* pointer to the C library which will then free it.
The callback must be in some sense exposed to the user of my library (probably using closures), and I want to provide a Rust interface as convenient as possible (meaning accepting a String output if possible).
However, the C library complains when trying to free() a pointer coming from memory allocated by Rust, probably because Rust uses jemalloc and the C library uses malloc.
So currently I can see two workarounds using libc::malloc(), but both of them have disadvantages:
Give the user of the library a slice that he must fill (inconvenient, and imposes length restrictions)
Take his String output, copy it to an array allocated by malloc, and then free the String (useless copy and allocation)
Can anybody see a better solution?
Here is an equivalent of the interface of the C library, and the implementation of the ideal case (if the C library could free a String allocated in Rust)
extern crate libc;
use std::ffi::CString;
use libc::*;
use std::mem;
extern "C" {
// The second parameter of this function gets passed as an argument of my callback
fn need_callback(callback: extern fn(arbitrary_data: *mut c_void) -> *mut c_char,
arbitrary_data: *mut c_void);
}
// This function must return a C-style char[] that will be freed by the C library
extern fn my_callback(arbitrary_data: *mut c_void) -> *mut c_char {
unsafe {
let mut user_callback: *mut &'static mut FnMut() -> String = mem::transmute(arbitrary_data); //'
let user_string = (*user_callback)();
let c_string = CString::new(user_string).unwrap();
let ret: *mut c_char = mem::transmute(c_string.as_ptr());
mem::forget(c_string); // To prevent deallocation by Rust
ret
}
}
pub fn call_callback(mut user_callback: &mut FnMut() -> String) {
unsafe {
need_callback(my_callback, mem::transmute(&mut user_callback));
}
}
The C part would be equivalent to this:
#include <stdlib.h>
typedef char* (*callback)(void *arbitrary_data);
void need_callback(callback cb, void *arbitrary_data) {
char *user_return = cb(arbitrary_data);
free(user_return); // Complains as the pointer has been allocated with jemalloc
}
It might require some annoying work on your part, but what about exposing a type that implements Write, but is backed by memory allocated via malloc? Then, your client can use the write! macro (and friends) instead of allocating a String.
Here's how it currently works with Vec:
let mut v = Vec::new();
write!(&mut v, "hello, world");
You would "just" need to implement the two methods and then you would have a stream-like interface.

Resources