代码之家  ›  专栏  ›  技术社区  ›  smwikipedia

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

  •  3
  • smwikipedia  · 技术社区  · 14 年前

    我通过C/C++第五版& GT阅读和Windows;下面是一些引用:

    每个进程的虚拟地址空间是 分成几个部分。在x86 32位上 Windows,0x00000000的分区- 调用0x0000FFFF(包含) 空指针分配分区。 这个分区是用来帮助 程序员捕获空指针 作业。如果你的 一个进程试图从或 写入此中的内存地址 分区,访问冲突是 提高。

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

    非常感谢。

    4 回复  |  直到 14 年前
        1
  •  4
  •   Jan Gray    14 年前

    所有现代操作系统都巧妙地使用虚拟内存管理硬件实现了一个空指针取消引用检查,并且没有执行开销。第0个4 KB页(或在本例中为0-15页(总计64 KB))已设置,因此地址0(或0x00000FFF或0x0000fff)处的任何数据读写或指令执行都会立即导致访问冲突异常。

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

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

    那么,为什么Windows(post Win98)的空指针分配分区是64kb,而不是必需的最小4kb?Wyzard的答案也很适合捕捉空指针数组索引错误。

    *最新更新:回复:为什么是64 KB?--我问了一个应该了解Windows核心团队的人,他们说这可能是一个64kb区域,因为Windows将某些内存管理结构保持在64kb的分配粒度。为什么?我不知道,但也许陈雷蒙有答案: http://blogs.msdn.com/b/oldnewthing/archive/2003/10/03/55239.aspx . 真 的。*

        2
  •  3
  •   Wyzard    14 年前

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

    保留的空间可能有助于捕捉 myarray[n] 哪里 myarray 为空,或 mystruct->myfield 哪里 mystruct 为空。被访问的地址不一定是指针指向的地方,它可能在指针之后的某个地方。

        3
  •  0
  •   sharptooth    14 年前

    这个范围是必要的,以便于检测由于取消引用空指针和接近空指针而导致的错误。例如:

    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 是空指针,结果地址是 接近空值 使用“分区”技术可以很容易地捕获对它们的解引用。

        4
  •  0
  •   Chris Becke    14 年前

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

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

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