如果段错误不可恢复,为什么将其称为错误(而不是中止)?

2023-12-13

我对术语的以下理解是这样的

1)中断
是由硬件发起的“通知”,用于调用操作系统运行其处理程序

2)陷阱
是由软件发起的“通知”,用于调用操作系统运行其处理程序

3)故障
是处理器在发生错误但可恢复时引发的异常

4) 中止
是处理器在发生错误但不可恢复时引发的异常

为什么我们称其为segmentation fault而不是一个segmentation abort then?

分段错误
是当你的程序尝试访问内存时 操作系统尚未分配,或者以其他方式分配 不允许访问。

我的经验(主要是在测试时C代码)是任何时候程序抛出一个segmentation fault又回到了绘图板——是否有一种情况,程序员可以真正“捕获”异常并用它做一些有用的事情?


在 CPU 级别,现代操作系统不使用 x86 段限制来保护内存。 (事实上​​,即使他们想在长模式(x86-64)下也不能这样做;段基数固定为 0,限制为 -1)。

操作系统使用虚拟内存页表,因此越界内存访问的真正 CPU 异常是页面错误。

x86 手册称其为#PF(fault-code)例外,例如看例外情况清单add可以提高。有趣的事实:超出段限制访问的 x86 异常是#GP(0).

由操作系统的页面错误处理程序决定如何处理它。许多#PF异常发生是正常操作的一部分:

  • 写时复制映射已写入:复制页面并将其在页表中标记为可写,然后返回用户空间重试出错的指令。 (这是一种“软”页面错误,也称为“轻微”页面错误。)
  • 其他软页面错误,例如内核很懒,实际上没有更新页表来反映进程所做的映射。 (例如。mmap(2)没有MAP_POPULATE).
  • 硬页面错误:找到一些物理内存并从磁盘读取文件(文件映射或匿名页面的交换文件/分区)。

解决上述任何问题后,更新CPU自行读取的页表,并在必要时使该TLB条目无效。 (例如,有效但只读更改为有效+读写)。

仅当内核发现该进程在逻辑上确实没有任何映射到该地址(或者它是对只读映射的写入)时,内核才会传递SIGSEGV到这个过程。这纯粹是一个软件的事情,整理出硬件异常的原因后。


英文文本为SIGSEGV (from strerror(3)) 是“分段错误”在所有 Unix/Linux 系统上,这就是当子进程因该信号而死亡时(由 shell)打印的内容。

这个术语很好理解,因此尽管它主要只是由于历史原因而存在并且硬件不使用分段。

请注意,对于尝试在用户空间中执行特权指令(例如wbinvd or wrmsr(写入特定型号寄存器))。在 CPU 级别,x86 例外是#GP(0)当您不在环 0(内核模式)时获取特权指令。

也适用于未对齐的 SSE 指令(例如movaps),尽管其他平台上的一些 Unix 会发送SIGBUS用于未对齐的访问故障(例如 SPARC 上的 Solaris)。


那么为什么我们称其为分段错误而不是分段中止呢?

It is可恢复的。它不会使整个机器/内核崩溃,它只是意味着用户空间进程试图执行内核不允许的操作。

即使对于出现段错误的进程can是可以恢复的。这就是为什么它是一个可捕捉的信号,与SIGKILL。通常,您不能只是恢复执行,而是可以有效地记录错误所在(例如,打印精确的异常错误消息,甚至堆栈回溯)。

SIGSEGV 的信号处理程序可以longjmp管他呢。或者,如果需要 SIGSEGV,则在从信号处理程序返回之前修改用于加载的代码或指针。 (例如。对于 Meltdown 漏洞利用,尽管有更有效的技术可以在错误预测或其他抑制异常的情况下执行链式加载,而不是实际让 CPU 引发异常并捕获内核提供的 SIGSEGV)

大多数编程语言(汇编语言除外)都不够低级,无法在围绕可能出现段错误的访问进行优化时提供明确定义的行为,从而让您编写可恢复的处理程序。这就是为什么如果您安装了 SIGSEGV 处理程序,通常除了在 SIGSEGV 处理程序中打印一条错误消息(可能还有堆栈回溯)之外,您不会做任何其他事情。


一些沙盒语言(如 Javascript)的 JIT 编译器使用硬件内存访问检查来消除 NULL 指针检查。在正常情况下,没有故障,因此故障情况下速度有多慢并不重要。

Java JVM 可以将SIGSEGV由 JVM 的线程接收到NullPointerException对于它运行的 Java 代码来说,JVM 没有任何问题。

  • 利用硬件陷阱有效消除空指针检查来自三位 IBM 科学家的关于 Java 的研究论文。

  • SableVM:6.2.4 各种架构上的硬件支持关于 NULL 指针检查

另一个技巧是将数组的末尾放在页面的末尾(后面是足够大的未映射区域),因此每次访问的边界检查都是由硬件免费完成的。如果您可以静态地证明索引始终为正,并且它不能大于 32 位,那么您就一切就绪了。

  • 64 位上的隐式 Java 数组边界检查 架构。他们讨论了当数组大小不是页面大小的倍数时该怎么做,以及其他注意事项。

陷阱与中止

我认为没有标准术语来区分。这取决于你所说的恢复类型。显然,在用户空间可以让硬件执行任何操作后,操作系统可以继续运行,否则非特权用户空间可能会使机器崩溃。

相关:开当中断发生时,流水线中的指令会发生什么情况?,Andy Glew(曾参与英特尔 P6 微架构的 CPU 架构师)表示,“陷阱”基本上是由正在运行的代码(而不是外部信号)引起的任何中断,并且是同步发生的。 (例如,当故障指令到达流水线的退休阶段而没有首先检测到较早的分支错误预测或其他异常时)。

“中止”不是标准的 CPU 架构术语。就像我说的,您希望操作系统无论如何都能继续运行,通常只有硬件故障或内核错误才能阻止这种情况。

AFAIK,“中止”也不是非常标准的操作系统术语。 Unix 有信号,其中一些是无法捕获的(如 SIGKILL 和 SIGSTOP),但大多数可以捕获。

SIGABRT可以被信号处理程序捕获。如果处理程序返回,进程就会退出,所以如果您不希望这样,您可以longjmp出来了。但据我所知,没有错误条件引发 SIGABRT;它只能通过软件手动发送,例如通过致电abort()库函数。 (它通常会导致堆栈回溯。)


x86 异常术语

如果您查看 x86 手册或osdev wiki 上的此异常表,在这种情况下有特定的含义(感谢@MargaretBloom 的描述):

  • trap:指令成功完成后引发,返回地址指向捕获实例之后。#DB调试和#OF溢出(into) 异常是陷阱。 (#DB 的某些来源是错误的)。但int 0x80或者其他软件中断指令也是陷阱,原样syscall(但它将返回地址放入rcx而不是推动它;syscall不是一个例外,因此从这个意义上来说并不是真正的陷阱)

  • fault:尝试执行后引发,然后回滚;返回地址指向错误指令。 (大多数异常类型都是故障)

  • abort是当返回地址指向不相关的位置时(即#DF双故障和#MC机器检查)。三重故障无法处理;当 CPU 尝试运行双故障处理程序时遇到异常,并且确实停止了整个 CPU 时,就会发生这种情况。

请注意,即使像 Andy Glew 这样的 Intel CPU 架构师有时也会更普遍地使用术语“陷阱”,我认为在讨论计算机架构理论时,它的意思是任何同步异常。不要指望人们会坚持使用上述术语,除非您实际上谈论的是处理 x86 上的特定异常。尽管它是有用且明智的术语,并且您可以在其他上下文中使用它。但如果你想做出区分,你应该澄清每个术语的含义,以便每个人都达成共识。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如果段错误不可恢复,为什么将其称为错误(而不是中止)? 的相关文章

  • Intel 64 和 IA-32 上的 MESI 有何意义

    MESI 的要点是保留共享内存系统的概念 然而 对于存储缓冲区 事情就变得复杂了 一旦数据到达 MESI 实现的缓存 下游内存就会保持一致 然而 在此之前 每个核心可能对内存位置 X 中的内容存在分歧 具体取决于每个核心的本地存储缓冲区中的
  • 如何知道寄存器是否是“通用寄存器”?

    我试图了解寄存器必须具备什么标准才能被称为 通用寄存器 我相信通用寄存器是一个可以用于任何用途的寄存器 用于计算 将数据移入 移出等 并且是一个没有特殊用途的寄存器 现在我读到了ESP寄存器是通用寄存器 我猜是ESP寄存器可以用于任何事情
  • 为什么我的空循环在 Intel Skylake CPU 上作为函数调用时运行速度是原来的两倍?

    我正在运行一些测试来比较 C 和 Java 并遇到了一些有趣的事情 在 main 调用的函数中 而不是在 main 本身中 运行具有优化级别 1 O1 的完全相同的基准代码 导致性能大约翻倍 我正在打印 test t 的大小 以毫无疑问地验
  • 确定分区属于什么文件系统

    操作系统如何知道分区正在使用什么文件系统 换句话说 FAT16 32 NTFS ext2 3等如何区分 如果您在 Windows 上使用 Win32 API 则可以调用 GetVolumeInformation http msdn micr
  • 程序集比较标志理解

    我正在努力理解汇编程序中的以下代码片段 if EAX gt 5 EBX 1 else EBX 2 在汇编程序中 可以写如下 根据我的书 模拟jge操作说明 https www felixcloutier com x86 jcc您通常会使用
  • 设置 IRQ 映射

    我正在遵循一些教程和参考文献来尝试设置我的内核 我在教程中遇到了一些不熟悉的代码 但根本没有解释它 这是我被告知映射的代码16 IRQs 0 15 到 ISR 地点32 47 void irq remap void outportb 0x2
  • 按字节数对向量进行混洗

    有什么办法可以左移 v 0 gt v 1 a m128i by n字节 其中n仅在运行时才知道 我目前仅限于 AVX1 但如果 AVX2 512 使这变得更容易 我非常感兴趣 I found mm bslli si128 m128i imm
  • 这个反斜杠在这段汇编代码中起什么作用?

    我不确定这些推线有什么区别 修剪下来来自 Linux 的 x86 entry calling h https github com torvalds linux blob 241e39004581475b2802cd63c111fec43b
  • 为什么 clang 使用 -O0 生成低效的 asm(对于这个简单的浮点和)?

    我正在 llvm clang Apple LLVM 版本 8 0 0 clang 800 0 42 1 上反汇编此代码 int main float a 0 151234 float b 0 2 float c a b printf f c
  • 是否可以在VM内使用VMX CPU指令?

    VM guest 内部的进程是否有可能使用 VMX AMD V VT x CPU 指令 然后由外部 VMM 处理而不是直接在 CPU 上处理 Edit 假设外部VM使用VMX本身来管理其虚拟客户机 即它在Ring 1中运行 如果可能的话 是
  • 了解多个进程的并发文件写入

    从这里 UNIX 中文件追加是原子的吗 https stackoverflow com questions 1154446 is file append atomic in unix 考虑多个进程打开同一个文件并向其追加内容的情况 O AP
  • 在 x86 程序集中存储大量布尔值的最佳方法是什么?

    最近我一直在处理充满布尔值的大型数组 目前 我将它们存储在 bss部分有一个 space指令 它允许我创建字节数组 但是 由于我只需要存储布尔值 因此我希望从数组中逐位读取和写入数据 目前 我能想到的最好方法是有一个 space指令所需存储
  • 在 x86 汇编中将 64 位常量移至内存

    我正在使用 Intel x64 程序集 NASM 编译器 尝试将 0x4000000000000000 常量移至内存 该常量在 ieee 754 标准双精度中应等于 2 0 我正在使用的代码是 define two 0x4000000000
  • 长多字节 NOP:通常理解的宏或其他符号

    x86 和 x86 64 处理器不仅具有单字节 这不是什么大秘密NOP指令 还包括各种类型的多字节类 NOP 指令 这些是我设法找到的 AMD 推荐 参考 AMD 系列 15h 处理器的 AMD 软件优化指南 文档 47414 http s
  • gdb查找行号的内存地址

    假设我已将 gdb 附加到一个进程 并且在其内存布局中有一个文件和行号 我想要其内存地址 如何获取文件x中第n行的内存地址 这是在 Linux x86 上 gdb info line test c 56 Line 56 of test c
  • 为什么 Linux perf 使用事件 l1d.replacement 来处理 x86 上的“L1 dcache misses”?

    在英特尔 x86 上 Linux用途 https stackoverflow com a 52172985 149138事件l1d replacements来实施其L1 dcache load misses event 该事件定义如下 计数
  • 避免 gcc 函数序言开销?

    我最近遇到了很多 gcc 在 x86 上生成非常糟糕的代码的函数 它们都符合以下模式 if some condition do something really simple and return else something comple
  • 为什么X86中没有NAND、NOR和XNOR指令?

    它们是您可以在计算机上执行的最简单的 指令 之一 它们是我亲自实施的第一个指令 执行 NOT AND x y 会使执行时间和依赖链长度和代码大小加倍 BMI1 引入了 andnot 这是一个有意义的补充 是一个独特的操作 为什么不是这个问题
  • 英特尔的最后分支记录功能是英特尔处理器独有的吗?

    最后分支记录是指存储与最近执行的分支相关的源地址和目标地址的寄存器对 MSR 的集合 它们受英特尔酷睿 2 英特尔至强和英特尔凌动处理器系列的支持 http css csail mit edu 6 858 2012 readings ia3
  • 模块参数权限

    我是内核编程的新手 当我正在经历module param 我对权限值 0 感到困惑 有人解释说它不会在 sysfs 中获得条目 而其他人则喜欢S IRUGO将获得一个条目 我无法理解这个概念 perm 值 0 表示什么 我们什么时候需要 s

随机推荐

  • 如何制作可折叠丝带?

    我正在寻找一种对可折叠丝带进行编程的方法 所以我这里有这段代码 ribbon position absolute top 20px right 0 padding 15px ribbon content position relative
  • 使用 Selenium 访问 Shadow DOM 树

    是否可以使用 Selenium Chrome webdriver 访问 Shadow DOM 中的元素 正如预期的那样 使用普通的元素搜索方法不起作用 我已经看到了对切换到子树w3c 上的规范 但找不到任何实际的文档 示例等 有人在这方面取
  • Networkx:绘制平行边

    使用以下代码从数据框中绘制图表 import pandas as pd import networkx as nx df pd DataFrame id emp 13524791000109 12053850000137 470782100
  • 禁用所有移动设备中的滚动

    这听起来好像互联网上应该有一个解决方案 但我不知道为什么我找不到它 我想禁用移动设备上的水平滚动 基本上试图实现这一目标 body overflow x hidden disable horizontal scrolling 这可能是相关信
  • 在matlab中将链接插入图像?

    我想在 matlab 中的图像中添加指向文档的链接 我有一个特定的区域 我想放置链接 例如 我希望图像中 x 40 y 120 处的位置有文档地址的链接 类似于下面的内容 我知道这不是正确的 matlab 代码 text 40 120 a
  • Qt和gcov,不生成覆盖率文件

    我正在尝试获取我为 Arora 浏览器编写的组件的代码覆盖率 该组件是使用 C 和 Qt 框架编写的 我无法使用 gcov 程序 无论是在 Gnu Linux 还是 Mac Os X 下 我尝试了在互联网上找到的所有内容 还通过强制自动编辑
  • Heroku rake db:migrate 不创建表 (Rails 5)

    我有一个 Rails 5 应用程序 我想销毁并重建我的实时数据库 网站尚未启动 所以我遵循了应该有效的步骤 它们过去曾经有效 heroku pg 重置 HEROKU POSTGRESQL HEROKUCOLOR URL confirm 应用
  • 如何在javascript中获取该元素的innerHTML?

    很简单的问题 我有一个元素 标签 它有一个 onclick 来调用 JavaScript 函数 除此之外 我希望这个函数能够回显调用它的元素的innerHTML 因此 在这种情况下 atag 的innerHTML 我该怎么做呢
  • 如何为组创建属性并在 hdf5 文件系统中访问它们?

    我想在 hdf5 文件中创建两个组 第一组 h5md团体简介和 颗粒 脂质组组2描述 前者仅包含一个直接属性 版本 1 0 和两个组创建者和作者及其属性 因此这里没有数据集 在 粒子 脂质组中 唯一缺少的部分是盒子组盒组说明 最少的信息是两
  • 如何围绕任意点旋转一组 2D 形状

    我正在创建一个 Body 类 它将一堆 2D 形状组合在一起 形成一个可移动 可旋转的主体 我需要知道的是如何旋转每个单独的形状 使其看起来像是整个身体都在旋转 而不是每个形状都围绕其中心旋转 我不能只是将每个形状的旋转中心更改为同一点 因
  • 带有开始和停止按钮的 Google Sheets 秒表

    我是 Google Apps Script 和 Java 的初学者 但我需要 Google Sheets 中的秒表 具有启动和停止功能 理想情况下 该按钮应该是一个切换按钮 这样我只需一个按钮即可启动和停止秒表 并且应该显示时间 有人可以帮
  • sizeToFit() 返回错误的高度 - 需要在 heightForRow 中查找单元格宽度

    我正在尝试根据内容制作具有动态单元格高度的 UITableView 我的应用程序是一个文章查看器 我尝试用这些函数计算单元格的高度 func heightForView text String font UIFont width CGFlo
  • 设置货币格式而不进行四舍五入

    我需要将十进制数字格式化为货币 但我不希望在此过程中发生任何舍入 例如 示例文化是 en US Dim money 1234 556789D money ToString C Yields 1 234 56 notice the round
  • 给定 N 个整数的绝对值,找到 N/2 个负值和 N/2 个正值的组合,其总和最接近 0

    假设我有一个包含 10 个数字的数组 其绝对值范围可以从 1 到 10 值可以重复 这方面的一个例子可能是 2 4 2 6 9 10 1 7 6 3 我们可以为每个数字分配一个正号或负号 但每个组合中应该始终有 5 个负数和 5 个正数 例
  • 如何使用OpenCV裁剪圆形图像?

    我想知道 openCV 中是否有一种方法可以让我在两个圆之间裁剪图像 从而忽略较小内圆中的所有内容和较大圆之外的所有内容 就像甜甜圈的形状 这是在 Python OpenCV 中执行此操作的一种方法 读取输入并获取其尺寸 定义两个圆的半径和
  • 右键单击节点上的 JTree 和下拉选项

    我正在尝试使用 JTree 并为所有父节点和子节点实现不同的下拉列表 这是我所做的 pmTree addMouseListener new java awt event MouseAdapter Override public void m
  • 我无法在 .net (vb.net) webbrowser 控件中使用 websocket

    我正在尝试在 Webbrowser 控件内运行网页 其中包含与 Websocket 的连接 该控件无法连接到 Websocket 当我在IE中测试时 一切运行正常 但在Visual Studio内的Webbrowser控件中 页面无法连接到
  • 在未连接的计算机上使用 git

    我有时会在两台未连接的计算机上进行开发的项目 一个典型的例子是在 BIDS 中创建报告 工作流程如下所示 我在公司 TFS 中创建一个项目 文件夹 使用git tfs创建本地git仓库 开发报告并提交到本地存储库 以及一些到 tfs 的签入
  • 在嵌套 JAR 内的文件夹中查找文件名

    当我的应用程序打包为 JAR 时 我无法访问目标文件夹 images 我不是在获取单个文件后 我想要的是 images 文件夹中所有 jpg 文件的列表 我试过这个 URI uri getClass getClassLoader getRe
  • 如果段错误不可恢复,为什么将其称为错误(而不是中止)?

    我对术语的以下理解是这样的 1 中断是由硬件发起的 通知 用于调用操作系统运行其处理程序 2 陷阱是由软件发起的 通知 用于调用操作系统运行其处理程序 3 故障是处理器在发生错误但可恢复时引发的异常 4 中止是处理器在发生错误但不可恢复时引