2015-05-25 8 views
7

Voglio passare in un String a un lib di Rust, ma genera sempre un errore di segmentazione.Errore di segmentazione quando si chiama un lib di Rust con Ruby FFI

Ecco il codice:

// lib.rs 
#[no_mangle] 
pub extern fn process(foo: String) -> String { 
    foo 
} 

e il file Rubino:

# embed.rb 
require 'ffi' 

module Hello 
    extend FFI::Library 
    ffi_lib 'target/release/libembed.dylib' 
    attach_function :process, [ :string ], :string 
end 

puts Hello.process("foo") 

risposta

6

Disclaimer: Non ho mai usato prima Ruby-FFI; Sto andando su quello che posso trovare nella documentazione.

Secondo lo Ruby-FFI wiki page on types, :string equivale a una stringa C con terminazione NUL. Questo è non lo stesso di un Rust String. A String in Rust è (attualmente) tre volte più grande!

Il tipo corrispondente in Ruggine sarebbe *const ::libc::c_char. Di nota, c'è anche std::ffi::CString, che è stato progettato per la creazione di stringhe C, e std::ffi::CStr che è il tipo di wrapper sicuro che può essere creato da a CString o *const c_char. Notare che nessuno di questi è compatibile con *const c_char!

In sintesi, per gestire le stringhe C in Rust, dovrete manipolare i tipi. Inoltre, tieni presente che, a seconda di ciò che stai effettivamente cercando di fare, potresti dover gestire anche la gestione manuale della memoria utilizzando libc::malloc e libc::free.

This answer to "Rust FFI C string handling" fornisce ulteriori dettagli su come gestire le stringhe C in Rust. Sebbene il contesto per la domanda si stia integrando con il codice C, dovrebbe essere ugualmente utile nel tuo caso.

+3

"Una stringa in ruggine è (attualmente) tre volte più grande!" è tecnicamente vero, nel senso che una stringa è un puntatore e due numeri interi e un 'char *' è un puntatore. Ma questo non significa che "lolfoobarthisisastring" sia tre volte più grande in Rust che in C. –

+0

Grazie, la tua risposta mi ha indirizzato nella giusta direzione. Mi sono imbattuto in https://github.com/vrinek/ruby-rust-examples/tree/master/messages. Sebbene dovessi adattare l'esempio alla nuova versione ruggine, avrei potuto farlo funzionare. – xijo

+0

Divertente nota a margine: la mia implementazione della ruggine è molto più lenta del mio puro rubino. Accidenti curva di apprendimento: D – xijo

0

Questo avviene perché le definizioni di "stringa" in Ruby e ruggine non corrispondono.

Ruby FFI si aspetta che sia un char* da C, ovvero un puntatore alla matrice di caratteri (funzione see here, create_object). Quindi Ruby tenta di dereferenziarlo come puntatore per ottenere dati sui personaggi e fallisce, perché non è realmente un puntatore.

Ruggine ha il suo String classe che non è solo char* da C. Esportazione stringhe da Rust in forma di puntatori è difficile e sufficientemente generico per deserve a separate question, e this answer vi possono aiutare.

+0

Questo non è corretto: CString è * tre puntatori di larghezza *. –

+1

@DK. vero. Qualcuno [sembra aver già avuto il tempo di spiegare] (http://stackoverflow.com/a/24148033/2076787) come farlo. –

+0

Grazie; Ho aggiunto il link alla mia risposta. –

Problemi correlati