我试图用Rust代码覆盖/包装Libc vprintf(format, va_list)函数。为此,我需要将VaList参数传递到不安全的代码中,该代码还需要捕获展开错误:

#![feature(c_variadic)]
extern crate libc;

use libc::{c_char, c_int};

pub unsafe extern "C" fn vprintf(format: *const c_char, args: std::ffi::VaList) -> c_int {
    if true {
        ::std::panic::catch_unwind(|| hook_fn(format, args)).ok()
    } else {
        None
    }
    .unwrap_or_else(|| hook_fn(format, args))
}

pub unsafe fn hook_fn(format: *const c_char, args: std::ffi::VaList) -> c_int {
    0
}

fn main() {
    println!("Hello, world!");
}

我的代码无法编译:
error[E0277]: the type `&mut std::ffi::VaListImpl<'_>` may not be safely transferred across an unwind boundary
   --> src/main.rs:8:9
    |
8   |         ::std::panic::catch_unwind(|| hook_fn(format, args)).ok()
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------ within this `[closure@src/main.rs:8:36: 8:60 format:&*const i8, args:std::ffi::VaList<'_, '_>]`
    |         |
    |         `&mut std::ffi::VaListImpl<'_>` may not be safely transferred across an unwind boundary
    |
    = help: within `[closure@src/main.rs:8:36: 8:60 format:&*const i8, args:std::ffi::VaList<'_, '_>]`, the trait `std::panic::UnwindSafe` is not implemented for `&mut std::ffi::VaListImpl<'_>`
    = note: `std::panic::UnwindSafe` is implemented for `&std::ffi::VaListImpl<'_>`, but not for `&mut std::ffi::VaListImpl<'_>`
    = note: required because it appears within the type `std::ffi::VaList<'_, '_>`
    = note: required because it appears within the type `[closure@src/main.rs:8:36: 8:60 format:&*const i8, args:std::ffi::VaList<'_, '_>]`

最佳答案

如果在 panic 之后使用某些类型,尤其是FFI类型,可能会导致未定义的行为。此安全性由类型是否实现UnwindSafe而不是VaList来跟踪。
错误消息的第一条“帮助”行对此进行了说明:

= help: within `[closure@src/main.rs:8:36: 8:61 format:&*const i8, args:std::ffi::VaList<'_, '_>]`,
the trait `std::panic::UnwindSafe` is not implemented for `&mut std::ffi::VaListImpl<'_>`
第一个“注释”还为您提供了可能的解决方案:
note: `std::panic::UnwindSafe` is implemented for `&std::ffi::VaListImpl<'_>`, but not for `&mut std::ffi::VaListImpl<'_>`
它告诉您是安全的,可以跨展开边界共享对VaListImpl的不可变引用。因此,您可以改为通过引用传递值来修复代码:
pub unsafe extern "C" fn vprintf(format: *const c_char, args: std::ffi::VaList) -> c_int {
    if true {
        ::std::panic::catch_unwind(|| hook_fn(format, &args)).ok()
    } else {
        None
    }
    .unwrap_or_else(|| hook_fn(format, &args))
}

pub unsafe fn hook_fn(format: *const c_char, args: &std::ffi::VaList) -> c_int {
    0
}

关于error-handling - 如何为VaList修复 “may not be safely transferred across an unwind boundary”?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63085993/

10-13 07:31