代码之家  ›  专栏  ›  技术社区  ›  Norman Ramsey

为什么derefrences(char*)0的Linux程序不总是segfault?

  •  6
  • Norman Ramsey  · 技术社区  · 15 年前

    我正在测试设计用于检测子进程何时出现segfaulted的代码。想象一下,当这个代码不总是segfault时,我会感到惊讶:

    #include <stdio.h>
    
    int main() {
      char *p = (char *)(unsigned long)0;
      putchar(*p);
      return 0;
    }
    

    我运行的是DebianLinux2.6.26内核;我的shell是AT&T ksh93 从Debian ksh 组件,版本M 93S+2008-01-31。有时,这个程序会出错,但除此之外,它只会以非零的退出状态安静地终止,但没有消息。我的信号检测程序报告如下:

    segfault terminated by signal 11: Segmentation fault
    segfault terminated by signal 53: Real-time signal 19
    segfault terminated by signal 11: Segmentation fault
    segfault terminated by signal 53: Real-time signal 19
    segfault terminated by signal 53: Real-time signal 19
    segfault terminated by signal 53: Real-time signal 19
    segfault terminated by signal 53: Real-time signal 19
    

    在纯净的 KSH 显示SegFault也很少见:

    Running... 
    Running... 
    Running... 
    Running... 
    Running... 
    Running... Memory fault
    Running... 
    

    有趣的是, bash 每次都正确检测到SEG故障 .

    我有两个问题:

    1. 有人能解释这种行为吗?

    2. 有人能建议一个简单的C程序在每次执行时都能可靠地分段故障吗?我也试过了 kill(getpid(), SIGSEGV) 但是我得到了类似的结果。


    编辑: jbcreix有答案 :我的SegFault探测器坏了。我被愚弄是因为 KSH 有同样的问题。我尝试过 猛击 猛击 每次都是正确的。

    我的错误是我路过 WNOHANG waitpid() 我本应该过零的。我不知道我该怎么想!有人想知道是怎么回事 KSH 但这是一个单独的问题。

    3 回复  |  直到 11 年前
        1
  •  12
  •   mesmerizingr Heath Hunnicutt    11 年前

    写作 NULL 将可靠地隔离故障或总线错误。

    有时操作系统会将只读页映射到零地址。因此,有时你可以从 无效的 .

    尽管C定义了 无效的 地址是特殊的,该特殊状态的“实现”实际上由操作系统的虚拟内存(VM)子系统处理。

    Wine和Dosemu需要在 无效的 为了Windows兼容性。参见 mmap_min_addr 在Linux内核中重建一个不能这样做的内核。

    MMPAPMIN ADDR 目前是一个热门话题,因为一个相关的开发和公共火焰对linus(显然是linux的名气),从theo de raadt,OpenBSD的努力。

    如果你愿意这样给孩子编码,你可以随时打电话: raise(SIGSEGV);

    此外,您还可以从以下位置获得一个保证SEGAULT指针: int *ptr_segv = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, -1, 0);

    在哪里? PROT_NONE 是保留无法访问的内存的键。对于32位Intel Linux,页面大小为4096。

        2
  •  1
  •   pbos    15 年前

    我不知道为什么它没有始终如一的行为。我觉得读书不是那么挑剔。或者类似的,尽管我可能完全错了。

    尝试以空值写入。这对我来说似乎是一致的。我不知道你为什么要用这个。:)

    int main()
    {
        *(int *)0 = 0xFFFFFFFF;
        return -1;
    }
    
        3
  •  1
  •   Amir Afghani    15 年前

    第二个问题的答案来自 Wikipedia :

     int main(void)
     {
         char *s = "hello world";
         *s = 'H';
     }