2015-07-10 11 views
5

Sto cercando di imparare Rust (principiante nella programmazione di basso livello) e voglio tradurre un piccolo amplificatore di amplificazione lv2 (audio) plugin "amp.c" (C-code) da C a Ruggine . Ho effettivamente funzionato (here), ma quando termina l'host, valgrind dice che " 64 byte in 1 blocco sono definitivamente persi". Penso di sapere perché succede, ma non so come risolverlo.struct statico con stringhe C per plugin lv2

Prima ci si stanca di leggere, qui è la domanda finale:

Come posso allocare staticamente una struct che contiene una stringa C?

E qui è l'introduzione:

Perché succede (credo): Host carica la libreria e chiama lv2_descriptor()

const LV2_Descriptor* 
lv2_descriptor() 
{ 
    return &descriptor; 
} 

che restituisce un puntatore ad una struct allocati staticamente di tipo LV2_Descriptor,

static const LV2_Descriptor descriptor = { 
    AMP_URI, 
    ... 
}; 

che è definito come

typedef struct _LV2_Descriptor { 
    const char * URI; 
    ... 
} LV2_Descriptor; 

Perché è allocato in modo statico? Nel amp.c si dice:

E 'meglio definire i descrittori statico per evitare perdite di memoria e non portatili costruttori libreria condivisa e distruttori di pulire correttamente.

Tuttavia, ho tradotto lv2_descriptor() per Rust come:

#[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 
    } 

quindi non è allocato in modo statico e non ho mai libera, ecco il motivo per cui immagino valgrind lamenta?

Come sto cercando di risolverlo? Sto cercando di fare la stessa cosa in Rust come fa il codice C, ad esempio allocare staticamente la struct (all'esterno di di lv2_descriptor()). L'obiettivo è di essere pienamente compatibili con la libreria lv2, vale a dire "... per evitare perdite di memoria ..." ecc., Come si dice nella citazione, giusto? Così ho provato qualcosa di simile:

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, ...}; 

Ma questo non si compila, ci sono messaggi di errore come

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(); 

specifico problema/domanda:

Come posso allocare staticamente una struct che contiene una stringa C?

+2

Un * novizio nella programmazione di basso livello * che utilizza valgrind, comprende il suo rapporto e rintraccia la perdita di memoria? Mi tolgo il cappello, signore! –

+0

@Shepmaster: Grazie, non l'ho visto, è davvero lo stesso problema. Ho provato la risposta di ker e funziona perfettamente, quindi forse possiamo adattare la risposta di ker alla domanda originale ed eliminarla? – poidl

+0

@MatthieuM .: Beh, ho dovuto scrivere un programma Fortran di 1000 righe una volta per lavoro, e dovevo usare valgrind lì ... Credo che rispetto alla maggior parte delle persone qui sono ancora piuttosto un principiante :) – poidl

risposta

3

La risposta breve è che non lo fai per ora. Future Rust guadagnerà probabilmente questa abilità.

Ciò che si può fare è allocare staticamente una struttura che contiene puntatori nulli e impostare quei puntatori nulli su qualcosa di utile quando si chiama la funzione. Ruggine ha static mut.Richiede codice non sicuro, è non codificabile affatto ed è (per quanto a mia conoscenza) considerato un odore codice.

Proprio qui considero una soluzione alternativa al fatto che non vi è alcun modo per trasformare un &[T] in un *const T in una statica.

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 
    } 
} 
+0

Eccellente, I provato e il messaggio di Valgrind è scomparso. Grazie! Dovrei indicare per le persone interessate a lv2, che ci deve essere * no * newline '\ n' nella stringa amp_uri. Errore mio. – poidl