rust - Option<i32> 展开安全吗?

标签 rust ffi

我正在实现一个 C 库的包装器,它接受回调,并且回调将在 Rust 中实现。鉴于panicking in Rust when calling from C is undefined behavior ,我想在任何潜在的 Rust panic 进入 C 之前捕获它们。

我一直在阅读有关 std::panic::catch_unwind 的内容。包装器对性能敏感,我宁愿避免使用类似 Mutex 的类型。我想将我的结果保存在 Option<i32> 中并将其设置为 Some(value)在没有 panic 的情况下。 None将表明该函数未成功执行,因此一定发生了 panic 。

Option<i32>放松安全吗?如果不是,什么情况下会出现问题?我可以把它包在 std::panic::AssertUnwindSafe 里吗?

这是我使用 AssertUnwindSafe 的示例包裹整个封闭物。

use std::panic::{self, AssertUnwindSafe};

fn random_function_that_might_panic(a: i32) -> i32 {
    if a == 42 {
        panic!("did you forget a towel?");
    }
    a * 2
}

fn do_not_panic(a: i32) {
    let mut result = None;
    let unwind_state = panic::catch_unwind(AssertUnwindSafe(|| {
        result = Some(random_function_that_might_panic(a)); // get result, but this could panic
    }));
    match unwind_state {
        Ok(()) => {
            match result {
                Some(value) => {
                    println!("Result: {:?}", value);
                }
                None => {
                    // this should never happen...
                    println!("No result but no panic?");
                }
            }
        }
        Err(e) => {
            println!("caught panic: {:?}", e);
        }
    }
}

fn main() {
    do_not_panic(1);
    do_not_panic(2);
    do_not_panic(3);
    do_not_panic(42);
}

(请参阅上面的 playground 。)

我不知道如何包装 Option<i32>AssertUnwindSafe ,所以我在这里包裹了整个封闭物。我该如何包装 Option<i32>

最佳答案

Is Option<i32> unwind safe?

是的。当你可以问编译器时,就没有理由问人类这个问题:

fn implements<T: std::panic::UnwindSafe>() {}

fn main() {
    implements::<Option<i32>>();
}

您的真正问题应该是:

Is &mut Option<i32> unwind safe?

事实并非如此,但您可能已经知道了。我猜你在添加 AssertUnwindSafe 之前遇到了这个编译器错误这告诉你它不安全:

error[E0277]: the trait bound `&mut std::option::Option<i32>: std::panic::UnwindSafe` is not satisfied in `[closure@src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`
  --> src/main.rs:12:24
   |
12 |     let unwind_state = panic::catch_unwind(|| {
   |                        ^^^^^^^^^^^^^^^^^^^ the type &mut std::option::Option<i32> may not be safely transferred across an unwind boundary
   |
   = help: within `[closure@src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`, the trait `std::panic::UnwindSafe` is not implemented for `&mut std::option::Option<i32>`
   = note: required because it appears within the type `[closure@src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`
   = note: required by `std::panic::catch_unwind`

我会这样编写你的代码,因为它的值(value)是:

fn do_not_panic(a: i32) {
    let result = panic::catch_unwind(|| random_function_that_might_panic(a)).ok();

    match result {
        Some(value) => {
            println!("Result: {:?}", value);
        }
        None => {
            println!("caught panic");
        }
    }
}

没有可变变量,没有额外的嵌套,没有“这永远不应该发生”的评论。

另请参阅:

关于rust - Option<i32> 展开安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52300517/

相关文章:

rust - 无法使用 std::io::process::Command 执行 `tput` 命令

rust - 为什么不能在同一结构中存储值和对该值的引用?

rust - 为什么 Vec<T> 期望 &T 作为 binary_search 的参数?

c - 如何在 ST monad 中执行 FFI 调用

c - 如何创建代表 union 的 `ffi_type`?

rust - Rust函数中的 “return”关键字显式

rust - Rust 中的字符串连接

raspberry-pi - FFI 在 Racket 中具有依赖关系?

arrays - FFI 可以处理数组吗?如果是这样,怎么做?

c - DPDK 函数在从 Rust 调用时与从 C 调用时具有不同的输出