Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static struct with C strings for lv2 plugin [duplicate]

Tags:

static

rust

audio

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?

like image 665
poidl Avatar asked Jul 10 '15 06:07

poidl


1 Answers

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
     }
}
like image 192
oli_obk Avatar answered Nov 05 '22 07:11

oli_obk