【问题标题】:Rust: Segfault when executing specific line of code from a dynamically loaded libraryRust:从动态加载的库中执行特定代码行时出现段错误
【发布时间】:2014-12-23 12:06:48
【问题描述】:

我正在用 Rust 编写一个简单的基于插件的系统来获得一些使用该语言的技能和经验。我的系统动态加载库并在运行时执行它们以初始化每个插件。从动态加载的库中执行代码时,我遇到了一个有趣的段错误问题。

这是加载和运行插件初始化函数的代码:(这点工作正常)

pub fn register_plugins<'rp>(&'rp mut self)
{
    let p1 = match DynamicLibrary::open(Some("librust_plugin_1.so")) {
            Ok(lib) => lib,
            Err(error) => fail!("Could not load the library: {}", error)
    };
    let s1: extern "Rust" fn(&PluginSystem) = unsafe {
        match p1.symbol("init") {
            Err(error) => fail!("Could not load function init: {}", error),
            Ok(init) => mem::transmute::<*mut u8, _>(init)
        }
    };
    s1(&self.ps);
}

这是插件库中的初始化函数:

#[no_mangle]
pub fn init(ps:&mut PluginSystem)
{
    ps.register_plugin("ps1"); //<-- Segfault is in this method
    ps.add_new_hook_with_closure("onLoad", "ps1", "display greeting.", 10, test1);
    println!("Initialized plugin.");
}

如前所述,段错误发生在名为 ps 的 PluginSystem 结构的 register_plugin 函数中。这个结构是从调用方法中借来的(在第一个代码块中)。

这是PluginSystem中的register_plugin函数:

pub fn register_plugin(&mut self, plugin_name: &'s str)
{
    if ! self.plugins.contains_key(&plugin_name) {
        let hm = HashMap::new(); //<-- Segfault Here
        self.plugins.insert(plugin_name, hm);
    };
}

在此代码块中执行HashMap::new()时出现segfault;

我尝试过以不同的方式实现此功能,如下所示:

pub fn register_plugin(&mut self, plugin_name: &'s str)
{
    match self.plugins.entry(plugin_name) {
                Vacant(entry) => {
                        entry.set(HashMap::new()); //<-- Segfault Here
                    }
                Occupied(mut entry) => {  }
            }
}

但我遇到了完全相同的问题。

如果我跳过 register_plugin 函数,并在动态加载的库中运行其他代码,它工作正常。事实上,这个段错误的唯一代码是HashMap::new()

这是错误还是现有问题,还是我做错了什么?

更多信息: 我用调试符号编译了 rust,以便通过 HashMap 代码来查找问题。看起来它甚至没有尝试执行 new() 函数,在调试代码时,当单步执行 HashMap::new() 时,调试器直接在 unwind.rs 中执行此函数:

pub unsafe fn try(f: ||) -> ::core::result::Result<(), Box<Any + Send>> {
    let closure: Closure = mem::transmute(f);
    let ep = rust_try(try_fn, closure.code as *mut c_void,
                  closure.env as *mut c_void);
    return if ep.is_null() {
        Ok(())
    } else {
        let my_ep = ep as *mut Exception; //<-- Steps into this line
        rtdebug!("caught {}", (*my_ep).uwe.exception_class);
        let cause = (*my_ep).cause.take(); //<-- Segfaults Here
        uw::_Unwind_DeleteException(ep);
        Err(cause.unwrap())
    };

Segfault出现在cause.take()函数中,我认为是因为my_ep.cause为null或不可访问。所以有些东西正在产生一个无效的异常,try 函数正在阻塞它并给出段错误。这和从动态加载的库中调用HashMap代码有关,但不知道是什么关系。

感谢您的帮助。

编辑: 我的平台是 linux x64,截至昨天(2014 年 10 月 28 日),我使用的是 git master 新构建的 rust。

【问题讨论】:

  • 您使用的是什么平台?展开器(rust_try 最终依赖)高度特定于特定平台,每个展开器实现都有自己的怪癖。
  • 糟糕,忘记在问题中添加该内容。我使用的是 linux x64,昨天刚从 git master 生成 rust。
  • @AshleySommer:s1 的类型是错误的:它说fn(&amp;PluginSystem),但实际函数通过可变引用获取PluginSystem。您还需要将呼叫更改为 s1(&amp;mut self.ps)
  • @FrancisGagné 谢谢。我做了你建议的那些改变,虽然我仍然遇到与 HashMap::new() 相关的同样的段错误问题。
  • 对于那些关注的人,请参阅 reddit 线程 here 以获取有关此问题的更多讨论。我可以通过将HashMap 的这个实例更改为TreeMap 来解决问题,但是当在不同的HashMap 上调用contains_key 时,我在程序的其他地方(不是在插件中)得到另一个段错误。跨度>

标签: segmentation-fault rust dlopen dynamic-library


【解决方案1】:

我在 GitHub 上提出了一个关于此问题 (here) 的问题,测试用例最少,几个小时后就解决了。

基本上,这是因为 rustc 在构建可执行文件时默认为静态链接 libstd,而在构建库时默认为动态链接。 所以 main 使用的是静态 libstd,并且在运行时加载 plugin.so 时,插件使用动态 libstd。之后会出现奇怪的内存问题。

已通过将 -C prefer-dynamic 添加到 rustc 的主要可执行文件来修复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-09
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    • 2019-06-27
    • 1970-01-01
    相关资源
    最近更新 更多