You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PanicInfo的set_hook回调中恢复Panic展开?

在panic hook中正确处理可展开的panic

你遇到的核心问题是对panic hook的定位理解有误:panic hook的作用是观察panic事件,而非直接干预或恢复panic的展开流程。当can_unwind()返回true时,Rust运行时在执行完你的自定义hook后,会自动继续panic的展开逻辑,不需要手动调用resume_unwind。

为什么你的代码会触发内存错误

PanicInfo::payload()返回的是&(dyn Any + Send)类型的引用,它指向的是Rust运行时内部管理的panic payload内存,并非你可以用Box::from_raw直接接管的裸指针。你强制将引用转成Box的操作,会导致后续运行时尝试释放这块内存时,出现“指针未分配”的错误——因为这块内存的所有权根本不在你手里。

正确的实现方式

如果你想在保留默认panic回溯输出的同时,添加自定义日志逻辑,只需要在自定义hook中调用原本的默认hook即可。默认hook负责生成标准的回溯信息,你的代码负责自定义处理:

#![feature(panic_can_unwind)]

use std::panic;

#[no_mangle]
pub extern "C" fn hello_from_rust_impl() {
    println!("Hello from Rust!");
    panic!("hello_from_rust_impl panicked");
}

#[no_mangle]
pub extern "C" fn hello_from_rust() {
    // 保存默认的panic hook
    let default_hook = panic::take_hook();
    
    panic::set_hook(Box::new(move |info: &panic::PanicInfo<'_>| {
        // 自定义逻辑:打印panic信息和can_unwind状态
        let msg = match info.payload().downcast_ref::<&'static str>() {
            Some(s) => *s,
            None => match info.payload().downcast_ref::<String>() {
                Some(s) => &s[..],
                None => "Box<Any>",
            },
        };
        println!("Panic message is {} can_unwind {}", msg, info.can_unwind());
        
        // 调用默认hook,生成标准回溯信息
        default_hook(info);
    }));
    
    let t = std::thread::spawn(move || {
        hello_from_rust_impl();
    });
    std::thread::sleep(std::time::Duration::from_secs(1));
    let _ = t.join();
}

fn main() {
    hello_from_rust();
}

这段代码执行后,会先打印你的自定义信息,然后输出默认的panic回溯,同时运行时会正常执行panic展开流程(如果can_unwind为true)。

关于手动恢复展开的说明

Rust的panic hook设计并不支持手动恢复展开——因为resume_unwind需要的是Box<dyn Any + Send>类型的payload所有权,而hook只能获取payload的引用。强行转换所有权会破坏运行时的内存管理,导致你遇到的内存错误。如果确实需要控制panic的展开行为,应该在panic发生的上下文(比如catch_unwind)中处理,而非在全局hook里。

内容的提问来源于stack exchange,提问作者calvin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 07:27:27