取消引用空指针会导致未定义的行为。在实践中,通常意味着我的程序会崩溃。但为什么操作系统不会崩溃?因为如果我的程序取消引用空指针,并且我的程序由操作系统运行,那么,根据逻辑传递性规则,这意味着操作系统试图取消引用空指针。操作系统为什么不进入“未定义行为”状态?
答案 0 :(得分:11)
C ++标准没有定义行为,要么保证崩溃,要么做其他事情。这并不妨碍操作系统定义行为 - 它不是C ++程序,因此它不必遵守C ++程序的“规则” [1] 。即便如此,操作系统也不会取消引用指针本身。
在大多数现代平台上,访问解除引用指针的目标将导致内存管理硬件引发异常(通常称为“分段故障”或“保护故障”)。这是由内核捕获的,内核可以确定执行哪个进程,并终止进程或向其发送信号。
因此,在这样的平台上,取消引用空指针的进程的默认行为将是崩溃;操作系统本身没有任何理由崩溃。
[1] 我的意思是非正式的“规则”,程序应该是格式良好的,并避免未定义的行为 - 不要与C ++的正式“规则”混淆语言标准指定的实现。
答案 1 :(得分:3)
每个主要操作系统都会保护内存访问。您不能简单地编写一个程序来操作未分配给它的内存(假设指针未初始化,例如,它可能是任何地址)。因此,每次程序试图访问一些不属于它的地址空间时,操作系统都会发送一个信号来终止程序(导致最终着名的“分段错误”,任何C / C ++程序员都熟悉)。 / p>
答案 2 :(得分:2)
因为操作系统必须执行某些事情,而崩溃会导致相当糟糕的用户体验。
没有编写OS以在C标准的抽象机器上运行。它是为真实硬件编写的,它以真实的方式表现为标准称为“未定义”的不同情况,因此它可以(并且必须)将这些真实行为考虑在内。如果没有,操作系统会在不同的硬件上执行不同的操作,这会破坏拥有操作系统的目的,不是吗?
在您说“未定义的行为未定义之前,请让坏代码的用户破坏他们想要的东西”,想象一下单个意外缓冲区溢出的安全问题是否能够对整个服务器进行分段。
答案 3 :(得分:2)
首先,UB意味着“任何事情都可能发生”。实际上,现代操作系统提供内存保护 - 当程序尝试取消引用空指针时,该指针尝试触发CPU内部的中断,该中断由操作系统捕获并处理操作系统然后停止程序,然后继续运行,好像没有发生任何不良事件。
答案 4 :(得分:1)
UB没有逻辑传递规则。你的假设是错误的。
UB确实意味着任何事情都可能发生,因此在写得不好的操作系统上,您的程序可能会使操作系统崩溃。不要排除它。
此外,您的程序不会崩溃,因为您取消引用NULL
指针。它崩溃了,因为操作系统告诉它崩溃。
答案 5 :(得分:1)
操作系统设置一个故障处理程序,如果内存访问违反操作系统强加的规则(例如访问空地址),则会调用该故障处理程序。如果您的程序即将取消引用空指针,则会调用此错误处理程序,程序将在访问不允许的内存区域之前结束。所以你的程序实际上从来没有取消引用空指针,它在尝试时被捕获。
检测禁止内存访问的机制通常通过页面表或内存分段等硬件支持来完成。
如果操作系统内核本身取消引用空指针,它通常会在尝试执行此操作时暂停。您将获得蓝屏,内核oops或类似的。如果它继续下去,那实际上可能导致“未定义的行为”。
请注意,术语“未定义的行为”仅在C或类似语言中准确定义,处理器并不关心 - 通常如果您尝试访问您没有足够权限的内存区域会发生什么情况在架构的背景下非常明确地定义。
答案 6 :(得分:1)
因为大多数程序都以用户模式运行,并且操作系统以内核模式运行。内核模式靠近物理硬件(他们说接近金属)。内核模式程序(操作系统,某些服务,驱动程序等)在CPU的环0中运行。用户模式程序在更高的环上运行。在CS的环N上运行的用户模式程序无法访问运行在N以下任何内容的程序或内存。如果他们尝试,则不允许这样做!
所有程序都获取其逻辑地址,操作系统会分配它。当程序尝试读取或写入某些内存时,OS会执行逻辑到物理寻址。如果程序试图访问它没有权限的地址,操作系统将抛出异常。此异常可由程序本身(本地异常处理程序,在同一线程中)处理。如果没有,任何附加的全局异常处理程序如果本地EH不处理它,调试器也可能会出现。它取决于操作系统,如何/何时将异常路由到调试器和/或全局异常处理程序。如果OS允许本地/全局/调试器处理它,它还取决于异常类型(如空指针访问)。如果没有人处理它,操作系统将终止进程(并可能创建崩溃转储,分段故障核心转储)。
如果没有调试过程(特定于Windows),并且安装了某个调试器,操作系统可能允许用户对其进行调试。
如果内核模式程序做了令人讨厌的事情,它会取消操作系统。我不是Linux人,所以不知道Linux的行为。但是,在Windows的情况下,BSOD会使您的显示器变成蓝色!
答案 7 :(得分:0)
因为如果我的程序取消引用空指针,那么我的程序就是 然后,根据逻辑传递性规则,由OS运行, 这意味着操作系统试图取消引用空指针。为什么不呢 操作系统进入“未定义行为”状态?
这是错误的。有一种叫做内存保护的东西,那就是为什么你的程序被终止了。操作系统是否在保护自身(在内存使用方面)。
答案 8 :(得分:0)
对不起,“逻辑传递性”的规则是什么?操作系统旨在做的一件事是保护程序免受其他程序的不当行为的影响。特别是,O / S不会因为你的程序试图做一些愚蠢的事情而崩溃。
在没有内存保护的操作系统上,通过null(或任何无效)指针访问确实会导致O / S崩溃(如果O / S碰巧使用位置0来表示有趣的事情)。
但这与逻辑传递性无关。这与您的程序访问属于另一个程序的内存有关。在这种情况下,任何一个程序都可能崩溃。