我正在测试 Rust 库,在 C++ 代码中使用它们可能会出现恐慌。我有以下库:
Cargo.toml
:
[package]
name = "boom"
version = "0.1.0"
edition = "2018"
[dependencies]
libc = "0.2"
[lib]
crate-type=["staticlib"]
src/lib.rs
:
#[no_mangle]
pub extern "C" fn boom() {
panic!("Oh no, something went wrong!");
}
我正在使用
cargo build
构建它,并在以下 C++ 代码(boom.cpp
文件)中使用结果:
// g++ -g boom.cpp -L./target/debug -lboom -o boom
extern "C" {
void boom();
}
int main() {
boom();
}
结果是:
thread '<unnamed>' panicked at src/lib.rs:3:5:
Oh no, something went wrong!
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
fatal runtime error: failed to initiate panic, error 5
到目前为止一切顺利。
我正在尝试将这种恐慌捕获到我的 C++ 代码中。我尝试过以下方法:
// g++ -g boom.cpp -L./target/debug -lboom -o boom
#include <stdexcept>
extern "C" {
void boom();
}
int main() {
try
{
boom();
}
catch(const std::exception& e)
{
printf("exception captured\n");
}
}
但结果是相同的,而不是预期的
exception captured
消息。
C++ 代码中是否有任何方法可以捕获 Rust 库中生成的恐慌?或者,反过来说,有没有办法将 Rust 恐慌转换为 C++ 可捕获的异常?
Rust 没有 C++ FFI,只有 C FFI。
C 中没有异常,因此没有指定用于异常传播的 ABI。
因此,没有标准机制将异常从 Rust 传播到 C(或 C 到 Rust),这没有多大帮助,因为无论如何都没有办法与 C 中的异常交互。
Rust 也没有具体说明。让 C++ 异常跨 C 堆栈帧已经是一场赌博。
无论哪种情况,C 堆栈帧都不会生成任何用于处理展开的代码,因此在异常传播期间展开时不会执行清理,从而导致未定义的行为。在实践中,后果可能是从“正常工作”到“泄漏”再到“损坏状态”。
除非工具链保证显式兼容性,否则异常不应跨越语言边界。
通过在 FFI 边界手动或自动翻译它们。
即从 Rust 到 C++:
catch_unwind
将异常转换为错误。如果您忘记了,希望RFC 2945能够(通过中止)拯救您正在经历的事情。
从 C++ 到 Rust:
catch
将异常转换为错误。如果你忘记了,你就正式进入了未定义行为领域。祝你好运。