使用Ruby FFI调用Rust lib时出现分段错误

时间:2022-07-10 17:01:32

I want to pass in a String to a Rust lib, but it always throws a segmentation fault.

我想将一个String传递给Rust lib,但它总是会抛出一个分段错误。

Here's the code:

这是代码:

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

And the Ruby file:

和Ruby文件:

 # 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")

2 个解决方案

#1


6  

Disclaimer: I've never used Ruby-FFI before; I'm going on what I can find in the documentation.

免责声明:我之前从未使用过Ruby-FFI;我正在继续我在文档中找到的内容。

According to the Ruby-FFI wiki page on types, :string is equivalent to a NUL-terminated C string. This is not the same as a Rust String. A String in Rust is (presently) three times larger!

根据类型的Ruby-FFI wiki页面,:string相当于NUL终止的C字符串。这与Rust String不同。 Rust中的字符串(目前)大三倍!

The corresponding type in Rust would be *const ::libc::c_char. Of note, there is also std::ffi::CString, which is designed for creating C strings, and std::ffi::CStr which is the safe wrapper type which can be created from either a CString or a *const c_char. Note that neither of these is compatible with *const c_char!

Rust中相应的类型是* const :: libc :: c_char。值得注意的是,还有std :: ffi :: CString,它用于创建C字符串,std :: ffi :: CStr是安全的包装类型,可以从CString或* const c_char创建。请注意,这些都不与* const c_char兼容!

In summary, to deal with C strings in Rust, you're going to have to juggle the types. Also keep in mind that, depending on what you're actually trying to do, you may need to also deal with manually managing memory using libc::malloc and libc::free.

总之,要处理Rust中的C字符串,您将不得不处理类型。还要记住,根据您实际尝试的操作,您可能还需要使用libc :: malloc和libc :: free手动管理内存。

This answer to "Rust FFI C string handling" gives more details on how to deal with C strings in Rust. Although the context for the question is integrating with C code, it should be equally useful in your case.

对“Rust FFI C string handling”的回答提供了有关如何处理Rust中C字符串的更多细节。虽然问题的上下文是与C代码集成,但在您的情况下它应该同样有用。

#2


0  

That happens because definitions of "string" in Ruby and Rust don't match.

这是因为Ruby和Rust中“string”的定义不匹配。

Ruby FFI expects it to be a char* from C, that is, a pointer to array of characters (see here, create_object function). So Ruby attempts to dereference it as a pointer to get character data and fails, because it's not really a pointer.

Ruby FFI期望它是来自C的char *,也就是指向字符数组的指针(参见这里的create_object函数)。因此Ruby尝试将其取消引用作为获取字符数据的指针并失败,因为它实际上并不是指针。

Rust has its own String class that is not just char* from C. Exporting strings from Rust in form of pointers is tricky and generic enough to deserve a separate question, and this answer should help you out.

Rust有自己的String类,它不仅仅是来自C的char *。以指针的形式从Rust中导出字符串非常棘手且通用,足以得到一个单独的问题,这个答案可以帮助你。

#1


6  

Disclaimer: I've never used Ruby-FFI before; I'm going on what I can find in the documentation.

免责声明:我之前从未使用过Ruby-FFI;我正在继续我在文档中找到的内容。

According to the Ruby-FFI wiki page on types, :string is equivalent to a NUL-terminated C string. This is not the same as a Rust String. A String in Rust is (presently) three times larger!

根据类型的Ruby-FFI wiki页面,:string相当于NUL终止的C字符串。这与Rust String不同。 Rust中的字符串(目前)大三倍!

The corresponding type in Rust would be *const ::libc::c_char. Of note, there is also std::ffi::CString, which is designed for creating C strings, and std::ffi::CStr which is the safe wrapper type which can be created from either a CString or a *const c_char. Note that neither of these is compatible with *const c_char!

Rust中相应的类型是* const :: libc :: c_char。值得注意的是,还有std :: ffi :: CString,它用于创建C字符串,std :: ffi :: CStr是安全的包装类型,可以从CString或* const c_char创建。请注意,这些都不与* const c_char兼容!

In summary, to deal with C strings in Rust, you're going to have to juggle the types. Also keep in mind that, depending on what you're actually trying to do, you may need to also deal with manually managing memory using libc::malloc and libc::free.

总之,要处理Rust中的C字符串,您将不得不处理类型。还要记住,根据您实际尝试的操作,您可能还需要使用libc :: malloc和libc :: free手动管理内存。

This answer to "Rust FFI C string handling" gives more details on how to deal with C strings in Rust. Although the context for the question is integrating with C code, it should be equally useful in your case.

对“Rust FFI C string handling”的回答提供了有关如何处理Rust中C字符串的更多细节。虽然问题的上下文是与C代码集成,但在您的情况下它应该同样有用。

#2


0  

That happens because definitions of "string" in Ruby and Rust don't match.

这是因为Ruby和Rust中“string”的定义不匹配。

Ruby FFI expects it to be a char* from C, that is, a pointer to array of characters (see here, create_object function). So Ruby attempts to dereference it as a pointer to get character data and fails, because it's not really a pointer.

Ruby FFI期望它是来自C的char *,也就是指向字符数组的指针(参见这里的create_object函数)。因此Ruby尝试将其取消引用作为获取字符数据的指针并失败,因为它实际上并不是指针。

Rust has its own String class that is not just char* from C. Exporting strings from Rust in form of pointers is tricky and generic enough to deserve a separate question, and this answer should help you out.

Rust有自己的String类,它不仅仅是来自C的char *。以指针的形式从Rust中导出字符串非常棘手且通用,足以得到一个单独的问题,这个答案可以帮助你。