6

我正在测试旨在检测子进程何时出现段错误的代码。当这段代码并不总是段错误时,想象一下我的惊讶:

#include <stdio.h>

int main() {
  char *p = (char *)(unsigned long)0;
  putchar(*p);
  return 0;
}

我在 Debian Linux 2.6.26 内核下运行;ksh93我的外壳是来自 Debian软件包的 AT&T 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

在 pure 下运行ksh表明 segfault 也很少见:

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

有趣的是,bash每次都能正确检测到段错误

我有两个问题:

  1. 谁能解释这种行为?

  2. 任何人都可以建议一个简单的 C 程序,它会在每次执行时可靠地发生段错误吗?我也尝试过kill(getpid(), SIGSEGV),但我得到了类似的结果。


编辑:jbcreix 有答案:我的段错误检测器坏了。我被愚弄了,因为ksh有同样的问题。我尝试过bash并且bash每次都做对了。

我的错误是我传递WNOHANGwaitpid(),我应该传递零。我不知道我当时在想什么!有人想知道 是怎么回事ksh,但这是一个单独的问题。

4

3 回答 3

12

写入NULL可靠地发生段错误或总线错误。

有时操作系统会将只读页面映射到零地址。因此,您有时可以从NULL.

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

WINE 和dosemu 需要NULL为Windows 兼容性映射一个页面。请参阅mmap_min_addrLinux 内核以重建无法执行此操作的内核。

mmap_min_addr由于 OpenBSD 工作的 Theo de Raadt 的相关漏洞利用和对 Linus(显然是 Linux 的名声)的公开抨击,目前是一个热门话题。

如果您愿意以这种方式对孩子进行编码,您可以随时致电:raise(SIGSEGV);

此外,您可以从以下位置获取保证到段错误的指针: int *ptr_segv = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, -1, 0);

PROT_NONE保留无法访问的内存的关键在哪里。对于 32 位 Intel Linux,PAGE_SIZE 为 4096。

于 2009-11-14T19:43:08.760 回答
1

来自维基百科的第二个问题的答案:

 int main(void)
 {
     char *s = "hello world";
     *s = 'H';
 }
于 2009-11-14T19:49:32.473 回答
1

我不确定为什么它没有一致的行为。我认为阅读并不那么挑剔。或者类似的东西,尽管我可能完全错了。

尝试写为 NULL。这对我来说似乎是一致的。我不知道你为什么要使用它。:)

int main()
{
    *(int *)0 = 0xFFFFFFFF;
    return -1;
}
于 2009-11-14T19:41:26.453 回答