使用FFI将Rust的Vec转换为Ruby的Array会导致段错误

3

我正在尝试从外部 Rust 函数返回一个可以转换为 Ruby 数组的结构体,但当我尝试调用结构体的 #to_a 方法时,我遇到了段错误。

use libc::size_t;
#[repr(C)]
pub struct Array {
    len: libc::size_t,
    data: *const libc::c_void,
}

impl Array {
    fn from_vec<T>(mut vec: Vec<T>) -> Array {

        vec.shrink_to_fit();

        let array = Array { data: vec.as_ptr() as *const libc::c_void, len: vec.len() as libc::size_t };

        mem::forget(vec);

        array
    }
}

#[no_mangle]
pub extern fn get_links(url: *const libc::c_char) -> Array {

  // Get links

  let mut urls: Vec<String> = vec![];

  // push strings into urls vec

  // urls => collections::vec::Vec<collections::string::String>

  Array::from_vec(urls)
}

require 'ffi'

module Rust
  extend FFI::Library
  ffi_lib './bin/libembed.dylib'

  class NodesArray < FFI::Struct
      layout :len,    :size_t, # dynamic array layout
             :data,   :pointer #

      def to_a
          self[:data].get_array_of_string(0, self[:len]).compact
      end
  end

  attach_function :get_links, [:string], NodesArray.by_value
end

当我尝试在Ruby中使用此函数时,它会返回Fii :: NodesArray。我还可以从结构体中获取len和data。只有当我调用#to_a时才会发生段错误。

我不熟悉Ruby FFI,但是... lendata应该颠倒吗?在Rust中是datalen,但在Ruby中是lendata - DK.
嗯,说得有道理。但是我确信我曾经以正确的布局放置它们,但仍然出现了段错误。我会尝试切换一下并更新问题。 - mpiccolo
1
你现在在 Rust 源代码中有两个独立的 Array 结构体定义... 请发布你正在使用的代码。 - Adrian
2个回答

2

问题由Adrian指出,我将字符串推入了Vec中。FFI需要*const libc::c_char,可以从String转换得到。

let mut urls: Vec<*const libc::c_char> = vec![];

urls.push(CString::new(string_var.value.to_string()).unwrap().into_raw());

1

看起来FFI::Pointer#get_array_of_string有错误(或者它并不做我认为它应该做的事情)。如果我更改这行代码,你的代码对我有效:

self[:data].get_array_of_string(0, self[:len]).compact

转换为:

Array.new(self[:len]) {|i| self[:data].read_pointer[i * FFI::Pointer::SIZE].read_string }

1
作为一则附注,您可能希望考虑使用 std::ffi::CString 代替 String - Adrian
太棒了。谢谢Adrian。是的,CString才是我应该使用的。 - mpiccolo
但问题在于,我只得到了一个字符串数组,指向数组中的第一个字符串。所以我得到了一个看起来像这样的数组:["https://www.google.com/webhp?tab=ww", "www.google.com/webhp?tab=ww", "le.com/webhp?tab=ww", "ebhp?tab=ww", "=ww", "\t", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""] - mpiccolo
@mpiccolo 我无法想象这种情况为什么会发生。我建议您发布一个新问题,并提供一个完整的示例程序,您正在收到的输出以及您期望的输出。如果没有这些信息,帮助您将会很困难。 - Adrian
我已经发布了修复方法。你提醒我需要使用CString而不是String,指引了我正确的方向。 - mpiccolo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接