繁体   English   中英

如果我取消引用空指针,为什么操作系统不会崩溃?

[英]Why doesn't the OS crash if I dereference a null pointer?

取消引用空指针会导致未定义的行为。 在实践中,这通常意味着我的程序会崩溃。 但是为什么操作系统不会崩溃? 因为如果我的程序解引用了一个空指针,而我的程序是由操作系统运行的,那么,根据逻辑传递性规则,这意味着操作系统试图解引用一个空指针。 为什么操作系统不进入“未定义行为”状态?

C++ 标准没有定义行为,要么保证崩溃,要么做任何其他事情。 这并不妨碍操作系统定义行为——它不是 C++ 程序,因此它不必遵守 C++ 程序的“规则” [1] 即便如此,操作系统也不会取消对指针本身的引用。

在大多数现代平台上,访问解引用指针的目标会导致内存管理硬件引发异常(通常称为“分段错误”或“保护错误”)。 这是由内核捕获的,它可以确定哪个进程执行了该操作,并杀死该进程或向其发送信号。

因此,在这样的平台上,取消引用空指针的进程的默认行为将是崩溃; 操作系统本身没有任何理由崩溃。

[1]我的意思是程序应该格式良好并避免未定义行为的非正式“规则” - 不要与语言标准指定的 C++ 实现的正式“规则”混淆。

内存访问在每个主要操作系统中都受到保护。 您不能简单地编写一个程序来操作未为其分配的内存(假设指针未初始化,例如,它可以是任何地址)。 因此,每次程序尝试访问一些不属于它的地址空间时,操作系统都会发送信号以终止程序(导致最终著名的“分段错误”,任何 C/C++ 程序员都熟悉)。

因为操作系统必须做一些事情,而崩溃会导致相当糟糕的用户体验。

操作系统不是为了在 C 标准的抽象机器上运行而编写的。 它是为真实硬件编写的,这些硬件在标准称为“未定义”的不同情况下以真实的方式运行,因此它可以(并且确实必须)考虑这些真实行为。 如果没有,操作系统会在不同的硬件上表现不同,这违背了拥有操作系统的目的,不是吗?

在你说“未定义的行为是未定义的,让坏代码的用户破坏他们想要的东西”之前,想象一下单个意外缓冲区溢出能够导致整个服务器出现段错误的安全问题。

首先,UB的意思是“任何事情都可能发生”。 然而在实践中,现代操作系统提供内存保护- 当程序试图取消引用一个空指针时,该指针试图触发 CPU 内部的中断,该中断由操作系统捕获并处理,然后操作系统停止程序,然后继续运行,就好像没有发生任何坏事一样.

当涉及到 UB 时,没有逻辑传递性规则。 你的假设是错误的。

UB 确实意味着任何事情都可能发生,因此在编写不佳的操作系统上,您的程序实际上可能会使操作系统崩溃。 不要排除它。

此外,您的程序不会因为您取消引用NULL指针而崩溃。 它崩溃是因为操作系统告诉它崩溃。

操作系统设置了一个故障处理程序,如果内存访问违反了操作系统规定的规则,例如对空地址的访问,则会调用该处理程序。 如果您的程序将要取消引用空指针,则会调用此故障处理程序,并且程序将在访问不允许的内存区域之前结束。 因此,您的程序实际上从未取消引用空指针,它在尝试时被捕获。

检测被禁止的内存访问的机制通常是通过硬件支持来完成的,比如页表或内存分段。

如果操作系统内核本身取消引用一个空指针,它通常会在尝试这样做时停止。 您将看到蓝屏、内核 oops 或类似情况。 如果它继续下去,那实际上可能会导致“未定义的行为”。

请注意,术语“未定义行为”仅在 C 或类似语言中完全定义,处理器并不真正关心 - 通常如果您尝试访问您没有足够权限的内存区域会发生什么是非常明确的在架构的背景下。

因为大部分程序运行在用户态,而操作系统运行在内核态 内核模式靠近物理硬件(他们说靠近金属)。 内核模式程序(操作系统、某些服务、驱动程序等)在 CPU 的环 0 中运行。 用户模式程序在更高的环上运行。 运行在 CPU 环 N 上的用户模式程序,不能访问运行在小于 N 的任何程序或内存上的程序或内存。如果他们尝试,他们将不被允许!

所有程序都获得它们的逻辑地址,然后操作系统分配它。 当程序尝试读取或写入一些内存时,操作系统会执行逻辑到物理寻址。 如果程序试图访问它没有权限的地址,操作系统将抛出异常。 此异常可由程序本身处理(本地异常处理程序,在同一线程中)。 如果没有,任何附加的全局异常处理程序。 如果本地 EH 不处理它,调试器也可能会出现。 这取决于操作系统,如何/何时将异常路由到调试器和/或全局异常处理程序。 它还取决于异常的类型(如空指针访问),如果操作系统允许本地/全局/调试器处理它。 如果没有人处理它,操作系统将终止该进程(并可能创建崩溃转储、分段错误核心转储)。

如果进程没有被调试(特定于 Windows),并且安装了一些调试器,操作系统可能允许用户调试它。

如果内核模式程序做了一些令人讨厌的事情,它就会关闭操作系统。 我不是 Linux 人,所以不知道 Linux 的行为。 但是,在 Windows 的情况下,BSOD 会用蓝色使您的显示器变亮!

因为如果我的程序解引用了一个空指针,而我的程序是由操作系统运行的,那么,根据逻辑传递性规则,这意味着操作系统试图解引用一个空指针。 为什么操作系统不进入“未定义行为”状态?

这是错误的。 有一种叫做内存保护的东西,这就是你的程序被终止的原因。 操作系统是否在保护自己(在内存使用方面)。

抱歉,“逻辑传递性”的规则是什么? 操作系统设计要做的一件事是保护程序免受其他程序的不当行为。 特别是,操作系统不应该仅仅因为您的程序试图做一些愚蠢的事情而崩溃。

在没有内存保护的操作系统上,通过空(或任何无效)指针访问确实可能导致 O/S 崩溃(如果 O/S 碰巧使用位置 0 来做一些有趣的事情)。

但这与逻辑传递性无关。 这与您的程序访问属于另一个程序的内存有关。 在这些情况下,任何一个程序都可能崩溃。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM