关于进程地址空间中的空指针分配分区的问题

问题描述 投票:0回答:4

我正在阅读< Windows via C/C++ 5th edition >,下面是一些引文:

每个进程的虚拟地址空间是 分成多个分区。在 x86 32 位上 Windows,0x00000000的分区- 0x0000FFFF(含)被调用 空指针分配分区。 这个分区是为了帮助 程序员捕获 NULL 指针 作业。如果你的线程 aprocess 尝试读取或 写入此内存地址 分区,访问冲突是 举起。

我想知道,为什么我们必须使用地址空间的范围而不是仅使用值0来捕获NULL指针分配? AFAIK,NULL等于0。那么这样设计背后的考虑是什么?在这个范围内还有其他用户不应该触摸的东西吗?或者NULL不一定等于0?

非常感谢。

windows memory process
4个回答
4
投票

所有现代操作系统都使用虚拟内存管理硬件巧妙地实现空指针取消引用检查,而无需执行开销。 第 0 个 4 KB 页(或者在本例中为第 0-15 页(总共 64 KB))被设置,以便地址 0(或 0x00000FFF 或 0x0000FFFF)处的任何数据读取或写入或指令执行立即导致访问违规异常。

让我换一种说法。 将空指针取消引用捕获到 0,但允许数据引用(例如)地址 1,其成本将非常昂贵——因为您无法使用页粒度 VM 硬件,因此需要执行空指针比较和分支序列在许多指针取消引用之前。 通过使第一页或前几页不可访问,可以在虚拟机硬件中“免费”完成此检查。 缺点是您不能将这些第一页用于其他用途。

(理论上,可以使用充分优化的编译器来确定哪些指针取消引用不可能是空指针取消引用,但在出现如此聪明的编译器之前,必须使用未映射的 0 页技巧。)

那么为什么 Windows(Win98 之后)的空指针分配分区是 64 KB,而不是最低必需的 4 KB? Wyzard 的答案也为捕获空指针数组索引错误提供了一个很好的案例。

*** 最新更新:回复:为什么是 64 KB? -- 我询问了 Windows Core 团队中应该了解的人,他们说这可能是一个 64 KB 区域,因为 Windows 将某些内存管理结构保持在 64 KB 分配粒度。 这是为什么? 我不知道,但也许 Raymond Chen 有答案:https://devblogs.microsoft.com/oldnewthing/20031008-00/?p=42223。 哇。 ***


3
投票

在 C 或 C++ 语言中,NULL 始终等于 0,但源代码中作为指针值的 0 不一定对应于编译后的二进制文件中的所有零位。 然而,在 Windows 上,我相信空指针实际上都是零位。

保留的空间可能是为了帮助捕获诸如

myarray[n]
(其中
myarray
为空)或
mystruct->myfield
(其中
mystruct
为空)之类的内容。 被访问的地址不一定是指针指向的位置,它可能位于指针之后的某个位置。


0
投票

该范围对于轻松检测由于取消引用空指针和接近空指针而导致的错误是必要的。例如:

int startOffset = 1000; //start at 1000th element;
char* buffer = obtain();// happens to be null
for( int i = startOffset; buffer[i] != 0; i++ ) {
   //do stuff
}

请注意,在上面的示例中,空指针从未被取消引用。然而,由于

buffer
是一个空指针,导致地址接近空,并且可以使用“分区”技术轻松捕获对它们的取消引用。


0
投票

需要范围,因为当取消引用指向结构或类元素的指针时,访问的实际内存将是指针,加上结构中成员的偏移量。

struct Foo {
    int a;
    inb b;
}* Bar = 0;

Bar->b = 0;

在 int = 32 位编译器上,“b”成员将占结构体的 4 个字节,因此 Bar->b 将尝试访问地址 0x00000004。

© www.soinside.com 2019 - 2024. All rights reserved.