无法恢复的错误与 panic!

有时你的代码中会发生严重问题,而你无能为力。在这些情况下,Rust 提供了 panic! 宏。实际上,有两种方式会导致 panic:一种是执行某个操作使代码产生 panic(例如访问数组越界),另一种是显式调用 panic! 宏。无论哪种情况,都会在程序中引发 panic。默认情况下,这些 panic 会打印失败信息、展开栈帧、清理堆栈并退出程序。通过设置环境变量,你还可以让 Rust 在发生 panic 时显示调用栈,以便更容易定位问题源头。

响应 Panic 的栈展开或终止

默认情况下,当发生 panic 时,程序开始进行栈展开,也就是 Rust 会沿着调用链向上回溯,并清理每个函数中的数据。然而,回溯和清理工作量较大。因此,Rust 允许你选择立即终止程序作为替代方案,即不进行任何清理直接结束运行。

此时程序占用的内存将由操作系统负责回收。如果你的项目需要尽可能减小生成的二进制文件体积,可以通过在 Cargo.toml 文件相应的 [profile] 部分添加 panic = 'abort' 来切换为遇到 panic 时直接终止。例如,如果想要在发布模式下遇到panic就终止,可以这样写:

[profile.release]
panic = 'abort'

下面我们尝试在一个简单程序中调用 panic!

文件名:src/main.rs

fn main() {panic!("crash and burn");
}

运行该程序,会看到类似如下输出:

$ cargo runCompiling panic v0.1.0 (file:///projects/panic)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.25sRunning `target/debug/panic`thread 'main' panicked at src/main.rs:2:5:
crash and burn
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

panic! 的调用导致最后两行显示错误信息。第一行展示了我们的panic消息以及出错位置:src/main.rs:2:5 表示这是 src/main.rs 文件第 2 行,第 5 个字符处。

这里指示的位置属于我们的代码,如果跳转至该行,就能看到触发宏调用的那条语句。但有时候,panic! 调用可能是在被我们代码间接调用的其他库代码里,此时错误消息报告的是那个库文件及其对应行号,而非最终导致该宏被触发的我们自己的源码位置。

我们可以利用产生这个panic!调用函数链上的回溯来找出引起问题的具体部分。为了理解如何使用这种backtrace,我们来看另一个例子,当因为我们的bug而从库内部触发了一个panic!而不是直接从自己代码里调动宏时,会是什么样子。列表9-1包含了一段尝试访问 vector 中超出有效索引范围元素的代码示例。

这里,我们试图访问向量的第100个元素(索引为99,因为索引从0开始),但该向量只有三个元素。在这种情况下,Rust 会发生 panic。使用 [] 应该返回一个元素,但如果传入了无效的索引,Rust 无法返回正确的元素。在 C 语言中,尝试读取数据结构末尾之外的数据是未定义行为。你可能会得到内存中对应那个位置的数据,即使那块内存不属于该数据结构。这被称为缓冲区溢出读取,如果攻击者能够操纵索引以读取他们不应该访问的数据,就可能导致安全漏洞。为了保护程序免受此类漏洞影响,如果你尝试读取不存在的索引处的元素,Rust 会停止执行并拒绝继续运行。我们来试试看:

$ cargo run
Compiling panic v0.1.0 (file:///projects/panic)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.27s
Running `target/debug/panic`
thread 'main' panicked at src/main.rs:4:6: index out of bounds: the len is 3 but the index is 99
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

这个错误指向 main.rs 的第4行,我们在这里尝试访问向量 v 中的索引99。
note 行告诉我们可以设置 RUST_BACKTRACE 环境变量来获取导致错误发生时的回溯信息。回溯是一系列调用函数列表,用于追踪到达当前点所经过的所有函数调用。Rust 中的回溯与其他语言类似:阅读回溯时应从顶部开始,一直读到看到自己编写文件的位置,那就是问题起源所在的位置。上方代码是你的代码调用过的,下方代码则是调用你的代码。这些上下文可能包括 Rust 核心代码、标准库或你使用的一些 crate。
让我们通过将 RUST_BACKTRACE 环境变量设置为非零值来获取回溯,如下所示:

$ RUST_BACKTRACE=1 cargo run
thread 'main' panicked at src/main.rs:4:6: index out of bounds: the len is 3 but the index is 99
stack backtrace:
0: rust_begin_unwind at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/panicking.rs:692:5
1: core::panicking::panic_fmt at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/core/src/panicking.rs:75:14
2: core::panicking::panic_bounds_check at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/core/src/panicking.rs:273:5
3:<usize as core::slice::index::SliceIndex<[T]>>::index at file:///home/.rustup/toolchains/1.85/lib/rustlib/src/rust/library/core/src/slice/index.rs :274 :10
4:core :: slice :: index::<impl core :: ops :: index :: Index<I> for [T]>::index 在 file:///home/.rustup/toolchains/1.85/lib/rustlib/src/rust/library/core/src/slice/index .rs :16 :9
...
note:部分细节已省略,可通过设置 `RUST_BACKTRACE=full` 获取详细完整回溯。

清单9-2:当环境变量 RUST_BACKTRACE 设置后,由 panic! 调用生成并显示出的回溯信息
输出内容非常多!具体输出可能因操作系统和 Rust版本不同而异。要获得带有这些信息的回溯,需要启用调试符号。当使用 cargo build 或 cargo run 且未加 --release 标志时,会默认启用调试符号,这正是我们的情况。
在清单9-2中的输出里,第6行指向项目中导致问题的位置——src/main.rs 文件第4行。如果不希望程序 panic,应从第一条提及自己编写文件路径的信息开始调查。在清单9-1中,我们故意写了会触发 panic 的代码,要修复它,只需避免请求超出向量范围之外的元素即可。当未来你的代码出现 panic 时,你需要弄明白是什么操作、什么数值导致了 panic,以及应该如何改正这段逻辑。
我们将在“是否应该使用 panic!”章节中进一步讨论何时以及为何应或不应使用 panic! 来处理错误情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/917255.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/917255.shtml
英文地址,请注明出处:http://en.pswp.cn/news/917255.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分享低功耗单火线开关语音识别方案

在众多老旧建筑和常规家居环境里&#xff0c;单火线布线是主流方式。单火线语音识别芯片方案通过研发和应用特殊的单火线语音识别芯片&#xff0c;实现设备在单火线供电条件下稳定运行&#xff0c;并精准识别语音指令&#xff0c;为智能家居、智能照明等领域带来便捷的语音控制…

如何在Windows操作系统上通过conda 安装 MDAnalysis

MDAnalysis 是一个开源的 Python 库,旨在提供一个高效且灵活的方式来分析和处理分子动力学(MD)模拟数据。它可以从不同的文件格式中读取模拟轨迹和结构数据,进行复杂的数据处理和分析,广泛应用于生物物理学、化学、材料科学等领域。 一、创建虚拟环境 为了能够顺利安装,减…

实用PDF演示解决方案

它打破了传统阅 读模式&#xff0c;让PDF文档也能像PPT一样流畅播放&#xff0c;特别适合汇报、讲解等展示场景。它是绿色单文件版&#xff0c;无需安装&#xff0c;双击红色图标即点即用。运行后第一件事&#xff0c;建议把界面语言切换成中文&#xff0c;操作更顺手。导入PDF…

VS Code中如何关闭Github Copilot

点击顶部搜索栏后面的Copilot图标&#xff0c;在下拉菜单中选择Hide Copilot。在弹出的提示框中&#xff0c;点击Hide Copilot按钮就可以了。

MySQL学习从零开始--第六部分

Binlog是什么&#xff1f;有哪几种格式&#xff1f;推荐使用哪种&#xff0c;为什么 Binlog是什么 Binlog二进制日志是MySQL Server层记录所有更改数据库内容的操作日志的二进制文件&#xff0c;如操作UPDATE,DELETE,INSERTBinlog不记录SELECT&#xff0c;SHOW等查询操作使主从…

走进computed,了解computed的前世今生

computed&#xff08;计算属性&#xff09;并不是vue独创的&#xff0c;而是源自计算机科学和响应式编程的长期发展 计算理论的奠基&#xff1a; 函数式编程的纯函数思想&#xff1a;计算属性的核心特征&#xff08;无副作用、依赖输入确定输出&#xff09;直接来源于函数式编程…

Java 23 新特性解析与代码示例

Java 23 新特性解析与代码示例 文章目录Java 23 新特性解析与代码示例1. 引言2. 正式特性2.1. Markdown文档注释 (JEP 467)2.2. 废弃sun.misc.Unsafe的内存访问方法以移除 (JEP 471)2.3. ZGC&#xff1a;默认启用代际模式 (JEP 474)3. 预览特性3.1. 原始类型在模式、instanceof…

spring boot + mybatis + mysql 只有一个实体类的demo

使用MyBatis进行数据库操作&#xff0c;配置简单。主要演示了mybatis可以不用只使用方法名来对应mapper.java和mapper.xml。 目录结构 pom.xml src/ ├── main/ │ ├── java/ │ │ └── com/ │ │ └── springbootjdbcweb/ │ │ └── …

iRemovalPro完美绕iCloud插卡打电话,A12+支持iOS 18.1.1

iRemovalPro 专业工具全解析与操作指南 &#xff08;支持iOS 14.0 - 16.6.1&#xff0c;A7-A15芯片设备&#xff09; &#x1f449;下载地址见文末 iRemoval Pro iRemoval 专业版是一款来自外国安全研究员的工具&#xff0c;用来帮助一些人因为忘记自己的ID或者密码&#xff0c…

安卓SELinux策略语法

目录前言一、 通用AV规则语法1.1 allow source target:class permissions;1.2 neverallow source target:class permissions;二、type三、attribute四、typeattribute五、alias六、typealias七、init_daemon_domain7.1 init_daemon_domain 宏概述7.2 宏展开与实现7.2.1 展开后规…

vscode cursor配置php的debug,docker里面debug

VSCode PHP调试配置指南 概述 本文介绍如何在VSCode中配置PHP调试环境&#xff0c;包括本地和Docker环境。 前置要求 VSCodePHP 7.0Xdebug扩展PHP Debug VSCode扩展 本地调试配置 1. 安装Xdebug # Ubuntu/Debian sudo apt-get install php-xdebug# MacOS brew install p…

elk部署加日志收集

清华大学镜像源地址&#xff1a;Index of /elasticstack/8.x/yum/8.13.2/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 一、elasticsearch 1.安装 rpm -ivh elastic-agent-8.13.2-x86_64.rpm 2.修改配置 vim /etc/elasticsearch/elasticsearch.yml 修改如下&…

dify 升级1.7.1 插件无法下载依赖

dify 升级1.7.1 插件无法下载依赖 1. 安装通义千问插件&#xff0c;各种报错&#xff1b; 使用下面命令查看docker 镜像日志 docker logs -f --tail100 docker-plugin_daemon-1 2025/08/01 07:42:21 full_duplex.go:59: [INFO]init environment for plugin langgenius/tongyi…

linux中简易云盘系统项目实战:基于 TCP协议的 Socket 通信、json数据交换、MD5文件区别与多用户文件管理实现

&#x1f4cb; 项目介绍 本项目是一个基于Linux环境的简易云盘系统&#xff0c;采用C/S&#xff08;客户端/服务器&#xff09;架构&#xff0c;实现了类似百度网盘的基本功能。系统通过TCP Socket进行网络通信&#xff0c;使用JSON格式进行数据交换&#xff0c;利用SQLite3数据…

linux中posix消息队列的使用记录

在linux中使用posix中的消息队列时遇到了一个问题&#xff0c;就是在发送消息时&#xff0c;如果队列满了&#xff0c;mq_send接口会一直阻塞&#xff0c;经过查找资料后才发现&#xff0c;该接口默认是阻塞的&#xff0c;也就是说&#xff0c;当队列满了以后&#xff0c;接口会…

01 基于sklearn的机械学习-机械学习的分类、sklearn的安装、sklearn数据集及数据集的划分、特征工程(特征提取与无量纲化、特征降维)

文章目录机械学习机械学习分类1. 监督学习2. 半监督学习3. 无监督学习4. 强化学习机械学习的项目开发步骤scikit-learn1 scikit-learn安装2 sklearn数据集1. sklearn 玩具数据集鸢尾花数据集糖尿病数据集葡萄酒数据集2. sklearn现实世界数据集20 新闻组数据集3. 数据集的划分特…

n8n】n8n的基础概念

以下是为初学者整理的 n8n 基本概念总结&#xff0c;帮助快速理解核心功能和使用逻辑&#xff1a;1. 工作流&#xff08;Workflow&#xff09;核心单元&#xff1a;n8n的一切操作基于工作流&#xff0c;代表一个自动化流程。组成&#xff1a;由多个节点&#xff08;Nodes&#…

机器学习基础-matplotlib

一、相关知识点二、plotfrom pylab import mpl # 设置显示中文字体 mpl.rcParams["font.sans-serif"] ["SimHei"] # 设置正常显示符号 mpl.rcParams["axes.unicode_minus"] False #%%#%% import matplotlib.pyplot as plt import random# 画出…

spring-ai-alibaba 学习(十九)——graph之条件边、并行节点、子图节点

前面了解了基础的概念及流程&#xff0c;以及一些参数类下面了解一些特殊的边和节点条件边常见的流程图可能长这个样子&#xff1a;其中菱形的为条件节点&#xff08;或者叫判定节点&#xff09;&#xff0c;但是在spring-ai-alibaba-graph中&#xff0c;并没有条件节点在sprin…

深入浅出设计模式——创建型模式之原型模式 Prototype

文章目录原型模式简介原型模式结构关于克隆方法&#xff1a;浅拷贝/深拷贝原型模式代码实例定义原型类和克隆方法客户端使用代码示例示例一&#xff1a;浅拷贝示例二&#xff1a;深拷贝原型模式总结开闭原则代码仓库原型模式&#xff1a;用原型实例指定创建对象的种类&#xff…