已知0地址(标记为宏'NULL')对访问不合法。 我想知道操作系统(比如linux)如何确定何时可以访问空地址,代码中的某处,而不必访问代码中的每个指针地址? 我认为它与信号有关,特别是“sigsegv”信号。操作系统如何在不检查所有指针地址的情况下确定空指针访问?
但我不知道它是如何完成的。
已知0地址(标记为宏'NULL')对访问不合法。 我想知道操作系统(比如linux)如何确定何时可以访问空地址,代码中的某处,而不必访问代码中的每个指针地址? 我认为它与信号有关,特别是“sigsegv”信号。操作系统如何在不检查所有指针地址的情况下确定空指针访问?
但我不知道它是如何完成的。
Memory Management Unit
在取消引用NULL
指针或访问无效地址时在异常触发中起着关键作用。
在MMU
对每个RAM
访问进行的正常虚拟到物理内存映射过程中,在MMU descriptors
中定义的虚拟地址范围内找不到未定义的地址。如果发生在操作系统内核空间中,或者只是在用户空间域中进行杀死和清理,这可能会造成灾难性后果。
...怎么回事操作系统(Linux的说)可以确定当有空地址的访问,在代码中的某处,,而无需在代码中访问每一个指针地址?
那么,操作系统无法在不访问指针的情况下确定NULL解引用。从wiki为分段错误:
在计算中,段故障(常缩写为段错误)或访问冲突是通过硬件具有存储器保护提出了一个故障,关于存储器通知操作系统(OS)访问违规;在x86计算机上,这是一种常规保护错误。操作系统内核将作出响应通常会执行一些纠正措施,通常通过向进程发送一个信号来将错误传递到违规进程。...
内存访问冲突是一个运行时事件,除非有一个无效的访问,没有办法操作系统会提高信号的过程。
FWIW,允许进程访问为其分配的内存(在虚拟地址空间中)。在分配的虚拟地址空间之外的任何地址(如果被访问)将产生故障(通过MMU),这反过来产生分段故障。
TL; DR - 在遇到NULL指针解引用时生成SIGSEV,而不是在此之前。此外,操作系统不会检测到本身的错误访问,而是通过raising a fault通知Memory Management Unit。
指针指的是虚拟地址空间。在虚拟地址空间中,内存的每个内存都可以映射到真实的物理内存。操作系统分别为每个进程处理此映射。
当您通过指针访问内存时,CPU会查看指针指定的虚拟地址的映射,并检查是否存在真实的物理内存。进行额外的检查来验证您是否具有对该内存的读取或写入权限,具体取决于您尝试的操作。
如果没有为该地址映射的内存,CPU会生成一个硬件中断。操作系统捕获该中断,并且 - 通常 - 为调用进程发出sigsegv信号。
包含NULL
地址的零页通常会故意保留未映射的位置,以便通常由编程错误导致的NULL指针访问很容易被捕获。
Linux从硬件获得此支持。处理器会被告知个别内存区域的用途及其可用性。如果访问“不可用”的内存区域,处理器会通知操作系统有关问题,操作系统会通知应用程序。
这意味着两件事情:
换句话说,如果指针指向“可用”内存的任何位置,则硬件单元无法识别问题。
首先空指针访问不一定是无效的。通常,操作系统的程序加载器或链接器(取决于系统)设置进程,以便虚拟地址空间中的最低页面未映射。
许多这样做的系统也允许应用程序映射第一页,使空引用有效。
NULL指针的检查方式与检查所有其他内存地址的方式相同:通过CPU的逻辑地址转换。
处理器每次访问内存(忽略缓存)时,都会查找进程页表中的地址。如果没有相应的条目,处理器会触发访问错误(在Unix中,变量会被转换为信号)。
如果地址在页表中有条目,处理器会检查页面允许的访问。如果您处于用户模式并尝试访问受内核保护的页面,则会触发故障。如果您尝试写入只读页面,则会触发错误。如果您尝试执行不可执行的页面,则会触发错误。
这是一个相当长的话题。如果您想了解有关该主题的更多信息,则需要了解逻辑内存翻译(有时候称为虚拟内存)。
但是有没有其他方法(除了sigsegv)找出一个null derefrence? –
@wannabeprogrammer可能在取消引用之前进行NULL检查? –