在OS会发生什么,当我们反引用在C中的NULL指针? [英] What happens in OS when we dereference a NULL pointer in C?

查看:124
本文介绍了在OS会发生什么,当我们反引用在C中的NULL指针?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设有一个指针,我们用NULL初始化。

Let's say there is a pointer and we initialize it with NULL.

int* ptr = NULL;
*ptr = 10;

现在,程序会崩溃,因为 PTR 不指向任何地址,我们会分配一个值给,这是一个无效的访问。所以,问题是,什么在操作系统内部发生?难道一个页面错误/分段故障发生的?将内核甚至在页表搜索?或之前崩溃发生的?

Now , the program will crash since ptr isn't pointing to any address and we're assigning a value to that , which is an invalid access. So , the question is , what happens internally in the OS ? Does a page-fault / segmentation-fault occur ? Will the kernel even search in the page table ? Or the crash occur before that?

我知道我不会做这样的事情在任何程序,但是这仅仅是知道在操作系统或编译器在这种情况下内部发生。它不是一个重复的问题。

I know I wouldn't do such a thing in any program but this is just to know what happens internally in the OS or Compiler in such a case. And it is NOT a duplicate question.

推荐答案

简短的回答:这取决于很多因素,包括编译器,处理器架构,具体的处理器型号,操作系统,等等。

Short answer: it depends on a lot of factors, including the compiler, processor architecture, specific processor model, and the OS, among others.

龙答案(86和x86-64):让我们下去的最低水平:CPU中。在x86和x86-64,即code通常会编译成一个像这样的指令或指令序列:

Long answer (x86 and x86-64): Let's go down to the lowest level: the CPU. On x86 and x86-64, that code will typically compile into an instruction or instruction sequence like this:

movl $10, 0x00000000

在高喊在虚拟内存地址0存放常整数10。在<一个href=\"http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html\">Intel® 64和IA-32架构软件开发手册详细时,该指令被执行会发生什么形容,所以我要总结一下你。

Which says to "store the constant integer 10 at virtual memory address 0". The Intel® 64 and IA-32 Architectures Software Developer Manuals describe in detail what happens when this instruction gets executed, so I'm going to summarize it for you.

CPU可以在几种不同的模式,其中有几个是用于向后兼容老得多的CPU运行。现代的操作系统上运行用户级code在一个叫做的保护模式的模式,它使用分页将虚拟地址转换成物理地址。

The CPU can operate in several different modes, several of which are for backwards compatibility with much older CPUs. Modern operating systems run user-level code in a mode called protected mode, which uses paging to convert virtual addresses into physical addresses.

对于每个进程,操作系统养了的页表的,这就决定了地址的映射方式。页表存储在存储器中的特定格式(和保护,使它们不能被用户code被修改),该CPU的理解。对于这种情况发生在每次存储器访问时,CPU根据页表转换它。如果翻译成功,则执行相应的读/写到物理存储器位置

For each process, the OS keeps a page table which dictates how the addresses are mapped. The page table is stored in memory in a specific format (and protected so that they can not be modified by the user code) that the CPU understands. For every memory access that happens, the CPU translates it according to the page table. If the translation succeeds, it performs the corresponding read/write to the physical memory location.

有趣的事情时,地址转换失败发生。不是所有的地址是有效的,如果有任何内存访问产生的无效地址,处理器引发的页故障异常的。这将触发从一个过渡的用户模式的(在x86 / x86-64的又名的当前特权级(CPL)3 的)转换成的内核模式的(即CPL 0)在内核中的code特定的位置,由中断描述符表定义的(IDT)。

The interesting things happen when the address translation fails. Not all addresses are valid, and if any memory access generates an invalid address, the processor raises a page fault exception. This triggers a transition from user mode (aka current privilege level (CPL) 3 on x86/x86-64) into kernel mode (aka CPL 0) to a specific location in the kernel's code, as defined by the interrupt descriptor table (IDT).

内核重新获得控制,并且基于从异常和进程的页表中的信息,计算出发生了什么。在这种情况下,认识到,用户级进程访问一个无效的内存位置,然后将其相应的反应。在Windows中,它会调用结构化异常处理允许用户code来处理异常。在POSIX系统,操作系统将提供一个 SIGSEGV 信号的过程。

The kernel regains control and, based on the information from the exception and the process's page table, figures out what happened. In this case, it realizes that the user-level process accessed an invalid memory location, and then it reacts accordingly. On Windows, it will invoke structured exception handling to allow the user code to handle the exception. On POSIX systems, the OS will deliver a SIGSEGV signal to the process.

在其他情况下,操作系统会在内部处理页面错误,并从当前位置重新启动的过程中,仿佛什么都没有发生。例如,保护页被放置在栈的底部,以允许在堆栈按需到一个限度生长代替preallocating大量存储器的堆栈。类似的机制用于实现写入时复制内存。

In other cases, the OS will handle the page fault internally and restart the process from its current location as if nothing happened. For example, guard pages are placed at the bottom of the stack to allow the stack to grow on demand up to a limit, instead of preallocating a large amount of memory for the stack. Similar mechanisms are used for achieving copy-on-write memory.

在现代操作系统中,页表通常设置,使地址0无效的虚拟地址。但有时它可能改变这种状况,例如在Linux上写0到伪文件的/ proc / sys目录/ VM / mmap_min_addr等多项,之后它可能使用的mmap(2)来映射虚拟地址0。在这种情况下,解引用一个空指针不会导致页面错误。

In modern OSes, the page tables are usually set up to make the address 0 an invalid virtual address. But sometimes it's possible to change that, e.g. on Linux by writing 0 to the pseudofile /proc/sys/vm/mmap_min_addr, after which it's possible to use mmap(2) to map the virtual address 0. In that case, dereferencing a null pointer would not cause a page fault.

以上的讨论是关于当原来的code在用户空间中运行会发生什么。但是,这也可能发生在内核里。内核可以(而且肯定是远远超过用户code更容易)映射虚拟地址0,所以这样的内存访问将是正常的。但是,如果它不映射,那么会发生什么则在很大程度上是相似的:在CPU引发的陷阱成predefined点内核中的页错误,内核检查发生了什么,并相应地作出反应。如果内核不能从异常中恢复,它通常会以某种方式惊慌(的内核恐慌内核哎呀的,或在Windows上,例如,一个BSOD)打印出一些调试信息发送到控制台或串行端口,然后停止。

The above discussion is all about what happens when the original code is running in user space. But this could also happen inside the kernel. The kernel can (and is certainly much more likely than user code to) map the virtual address 0, so such a memory access would be normal. But if it's not mapped, then what happens then is largely similar: the CPU raises a page fault error which traps into a predefined point at the kernel, the kernel examines what happened, and reacts accordingly. If the kernel can't recover from the exception, it will typically panic in some fashion (kernel panic, kernel oops, or a BSOD on Windows, e.g.) by printing out some debug information to the console or serial port and then halting.

另请参阅庸人自扰NULL:对于攻击者可以如何利用一个例子开拓内核NULL解除引用一个空指针引用错误,从以获得一个Linux机器上root权限在内核中。

See also Much ado about NULL: Exploiting a kernel NULL dereference for an example of how an attacker could exploit a null pointer dereference bug from inside the kernel in order to gain root privileges on a Linux machine.

这篇关于在OS会发生什么,当我们反引用在C中的NULL指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆