简体   繁体   English

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

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

Dereferencing a null pointer results in undefined behavior.取消引用空指针会导致未定义的行为。 In practice it usually means that my program will crash.在实践中,这通常意味着我的程序会崩溃。 But why doesn't the OS crash?但是为什么操作系统不会崩溃? Because if my program dereferences a null pointer, and my program is run by the OS, then, according to the rules of logical transitivity, this means the OS tried to dereference a null pointer.因为如果我的程序解引用了一个空指针,而我的程序是由操作系统运行的,那么,根据逻辑传递性规则,这意味着操作系统试图解引用一个空指针。 Why doesn't the OS enter a state of "undefined behavior"?为什么操作系统不进入“未定义行为”状态?

The C++ standard doesn't define the behaviour, either to guarantee a crash, or to do anything else. C++ 标准没有定义行为,要么保证崩溃,要么做任何其他事情。 That doesn't prevent the OS from defining the behaviour - it's not a C++ program, so it doesn't have to abide by the "rules" [1] of C++ programs.这并不妨碍操作系统定义行为——它不是 C++ 程序,因此它不必遵守 C++ 程序的“规则” [1] Even so, the OS won't dereference the pointer itself.即便如此,操作系统也不会取消对指针本身的引用。

On most modern platforms, accessing the target of the dereferenced pointer will cause the memory-management hardware to raise an exception (often called a "segmentation fault" or "protection fault").在大多数现代平台上,访问解引用指针的目标会导致内存管理硬件引发异常(通常称为“分段错误”或“保护错误”)。 This is caught by the kernel, which can determine which process did it, and either kill the process, or send it a signal.这是由内核捕获的,它可以确定哪个进程执行了该操作,并杀死该进程或向其发送信号。

So, on such a platform, the default behaviour of a process that dereferences a null pointer will be to crash;因此,在这样的平台上,取消引用空指针的进程的默认行为将是崩溃; there is no reason whatsoever for the OS itself to crash.操作系统本身没有任何理由崩溃。

[1] By which I mean the informal "rules" that a program should be well-formed and avoid undefined behaviour - not to be confused with the formal "rules" for C++ implementations specified by the language standard. [1]我的意思是程序应该格式良好并避免未定义行为的非正式“规则” - 不要与语言标准指定的 C++ 实现的正式“规则”混淆。

Memory access is protected in every major OS.内存访问在每个主要操作系统中都受到保护。 You cannot simply write a program that manipulates memory that was not allocated for it (assuming a pointer is not initialized for example, it could be ANY address).您不能简单地编写一个程序来操作未为其分配的内存(假设指针未初始化,例如,它可以是任何地址)。 So, every time a program tries to access some address space that does not belong to it, the OS will send a signal to terminate the program (resulting in the ultimate famous "Segmentation fault", familiar to any C/C++ programmer).因此,每次程序尝试访问一些不属于它的地址空间时,操作系统都会发送信号以终止程序(导致最终著名的“分段错误”,任何 C/C++ 程序员都熟悉)。

Because the OS has to do something , and crashing would make for a rather bad user experience.因为操作系统必须做一些事情,而崩溃会导致相当糟糕的用户体验。

The OS isn't being written to run on the abstract machine of the C standard.操作系统不是为了在 C 标准的抽象机器上运行而编写的。 It's being written for real hardware that behaves in real ways to different situations that the standard calls "undefined," so it can (and really must) take those real behaviors into account.它是为真实硬件编写的,这些硬件在标准称为“未定义”的不同情况下以真实的方式运行,因此它可以(并且确实必须)考虑这些真实行为。 If it didn't, the operating system would perform differently on different hardware, which kind of defeats the purpose of having an OS, doesn't it?如果没有,操作系统会在不同的硬件上表现不同,这违背了拥有操作系统的目的,不是吗?

And before you say "undefined behavior is undefined, let the user of bad code wreck what they want," imagine the security problems of a single accidental buffer overrun being able to segfault an entire server.在你说“未定义的行为是未定义的,让坏代码的用户破坏他们想要的东西”之前,想象一下单个意外缓冲区溢出能够导致整个服务器出现段错误的安全问题。

First of all, UB means "anything can happen".首先,UB的意思是“任何事情都可能发生”。 In practice however modern OSes offer memory protection - when a program tries to dereference a null pointer that attempt triggers an interrupt inside the CPU which is caught and handled by the OS and the OS then stops the program and then continues running as if nothing bad happened.然而在实践中,现代操作系统提供内存保护- 当程序试图取消引用一个空指针时,该指针试图触发 CPU 内部的中断,该中断由操作系统捕获并处理,然后操作系统停止程序,然后继续运行,就好像没有发生任何坏事一样.

There are no rules of logical transitivity when it comes to UB.当涉及到 UB 时,没有逻辑传递性规则。 Your assumption is wrong.你的假设是错误的。

UB does mean that anything can happen, so on a poorly written OS, your program might actually crash the OS. UB 确实意味着任何事情都可能发生,因此在编写不佳的操作系统上,您的程序实际上可能会使操作系统崩溃。 Don't rule it out.不要排除它。

Also, your program doesn't crash because you dereference a NULL pointer.此外,您的程序不会因为您取消引用NULL指针而崩溃。 It crashes because the OS tells it to crash.它崩溃是因为操作系统告诉它崩溃。

The OS sets up a fault handler which is called if a memory access violates rules imposed by the OS - such as an access to the null address.操作系统设置了一个故障处理程序,如果内存访问违反了操作系统规定的规则,例如对空地址的访问,则会调用该处理程序。 If your program is about to dereference a null pointer this fault handler is called and the program will be ended before it accesses the disallowed memory region.如果您的程序将要取消引用空指针,则会调用此故障处理程序,并且程序将在访问不允许的内存区域之前结束。 So your program does actually never dereference a null pointer, it is catched while trying.因此,您的程序实际上从未取消引用空指针,它在尝试时被捕获。

The mechanism for detecting forbidden memory accesses is often done with hardware support like page tables or memory segmentation.检测被禁止的内存访问的机制通常是通过硬件支持来完成的,比如页表或内存分段。

If the OS kernel itself dereferences a null pointer, it usually halted while trying to do so.如果操作系统内核本身取消引用一个空指针,它通常会在尝试这样做时停止。 You will get a blue screen, kernel oops or similar.您将看到蓝屏、内核 oops 或类似情况。 If it keeps going, that may actually result in "undefined behaviour".如果它继续下去,那实际上可能会导致“未定义的行为”。

Note that the term "undefined behaviour" is only exactly defined in C or similar languages, the processor doesn't really care - usually what happens if you try to access a memory region for which you don't have sufficient rights is very well defined in the context of the architecture.请注意,术语“未定义行为”仅在 C 或类似语言中完全定义,处理器并不真正关心 - 通常如果您尝试访问您没有足够权限的内存区域会发生什么是非常明确的在架构的背景下。

Because most of the programs run in user mode , and the OS runs in kernel mode .因为大部分程序运行在用户态,而操作系统运行在内核态 The Kernel mode is near to the physical hardware (they say close to the metal ).内核模式靠近物理硬件(他们说靠近金属)。 Kernel mode programs (OS, some services, drivers etc) runs in ring 0 of CPU.内核模式程序(操作系统、某些服务、驱动程序等)在 CPU 的环 0 中运行。 User mode programs runs on higher ring.用户模式程序在更高的环上运行。 User mode programs running on ring N of CPU, cannot access programs or memory running on anything less than N. If they try to, they wont be allowed!运行在 CPU 环 N 上的用户模式程序,不能访问运行在小于 N 的任何程序或内存上的程序或内存。如果他们尝试,他们将不被允许!

All programs get their logical address, and OS assigns it.所有程序都获得它们的逻辑地址,然后操作系统分配它。 OS does the logical to physical addressing when program tries to read or to write some memory.当程序尝试读取或写入一些内存时,操作系统会执行逻辑到物理寻址。 If program tries to access the address, which it doesn't have permission, the OS will throw the exception.如果程序试图访问它没有权限的地址,操作系统将抛出异常。 This exception may be handled by program itself (a local exception-handler, in same thread).此异常可由程序本身处理(本地异常处理程序,在同一线程中)。 If not, any attached global exception handler.如果没有,任何附加的全局异常处理程序。 Debugger may also come into picture, if local EH doesn't handle it.如果本地 EH 不处理它,调试器也可能会出现。 It depends on OS, how/when to route exception to debugger and/or to the global exception handler.这取决于操作系统,如何/何时将异常路由到调试器和/或全局异常处理程序。 It also depends on type of exception (like null-pointer access), if OS allows local/global/debugger to handle it or not.它还取决于异常的类型(如空指针访问),如果操作系统允许本地/全局/调试器处理它。 If no one handles it, the OS would terminate the process (and possibly creating crash dump, segmentation fault core dump).如果没有人处理它,操作系统将终止该进程(并可能创建崩溃转储、分段错误核心转储)。

If the process it not being debugged (Windows specific), and some debugger is installed, OS may allow user to debug it.如果进程没有被调试(特定于 Windows),并且安装了一些调试器,操作系统可能允许用户调试它。

If the kernel mode program does something nasty, it would take down the OS.如果内核模式程序做了一些令人讨厌的事情,它就会关闭操作系统。 I'm not Linux guy, so don't know behavior of Linux.我不是 Linux 人,所以不知道 Linux 的行为。 But, in case of Windows, BSOD would brighten your monitor with blue color!但是,在 Windows 的情况下,BSOD 会用蓝色使您的显示器变亮!

Because if my program dereferences a null pointer, and my program is run by the OS, then, according to the rules of logical transitivity, this means the OS tried to dereference a null pointer.因为如果我的程序解引用了一个空指针,而我的程序是由操作系统运行的,那么,根据逻辑传递性规则,这意味着操作系统试图解引用一个空指针。 Why doesn't the OS enter a state of "undefined behavior"?为什么操作系统不进入“未定义行为”状态?

This is wrong.这是错误的。 There's something called memory protection and thats WHY your program is terminated.有一种叫做内存保护的东西,这就是你的程序被终止的原因。 Is the OS that is protecting itself (in the terms of memory use).操作系统是否在保护自己(在内存使用方面)。

Sorry, what rules of 'logical transitivity'?抱歉,“逻辑传递性”的规则是什么? One of the things an operating system is designed to do is to protect programs from the misbehaviour of other programs.操作系统设计要做的一件事是保护程序免受其他程序的不当行为。 In particular, the O/S should not crash just because your program tries to do something silly.特别是,操作系统不应该仅仅因为您的程序试图做一些愚蠢的事情而崩溃。

On operating systems without memory protection, accessing via a null (or any invalid) pointer could indeed cause the O/S to crash (if the O/S happened to use location 0 for something interesting).在没有内存保护的操作系统上,通过空(或任何无效)指针访问确实可能导致 O/S 崩溃(如果 O/S 碰巧使用位置 0 来做一些有趣的事情)。

But that has nothing to do with logical transitivity.但这与逻辑传递性无关。 That has to do with your program accessing memory that belongs to another program.这与您的程序访问属于另一个程序的内存有关。 Either programs could crash in those circumstances.在这些情况下,任何一个程序都可能崩溃。

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

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