我正在testing旨在检测subprocess何时分离的代码。 想象一下,当这段代码不总是出现段错误时,我感到惊讶:
#include <stdio.h> int main() { char *p = (char *)(unsigned long)0; putchar(*p); return 0; }
我在Debian Linux 2.6.26内核下运行; 我的shell是来自Debian ksh
包的版本M 93s + 2008-01-31的AT&T ksh93
。 有时候这个程序会出现段错误,否则它会以一个非零的退出状态静静地终止,但是没有消息。 我的信号检测程序报告如下:
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
下运行表明,段错误也很罕见:
Running... Running... Running... Running... Running... Running... Memory fault Running...
有趣的是, bash
每次都正确地检测到段错误 。
我有两个问题:
任何人都可以解释此行为?
任何人都可以提出一个简单的C程序,可以在每次执行时可靠的segfault? 我也试过kill(getpid(), SIGSEGV)
,但是我得到了类似的结果。
编辑: jbcreix有答案 :我的段故障检测器被打破。 我被骗了,因为ksh
有同样的问题。 我试着用bash
和bash
每次都正确。
我的错误是,我正在把WNOHANG
传递给waitpid()
,在那里我应该传递零。 我不知道我能想什么 有人想知道ksh
是怎么回事,但这是一个单独的问题。
写入 NULL
将可靠地段错误或总线错误。
有时操作系统会将只读页面映射到零地址。 因此,你有时可以从NULL
读取。
尽管C将NULL
地址定义为特殊的,但是该特殊状态的“实现”实际上是由操作系统的虚拟存储器(VM)子系统处理的。
WINE和dosemu需要在NULL
映射一个页面,以便兼容Windows。 请参阅Linux内核中的mmap_min_addr
以重建不能执行此操作的内核。
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。
我不确定为什么它没有一致的行为。 我认为阅读并不挑剔。 或者类似的东西,虽然我可能是完全错误的。
尝试写在NULL。 这似乎是一致的我。 我不知道你为什么要使用这个。 🙂
int main() { *(int *)0 = 0xFFFFFFFF; return -1; }
来自维基百科的第二个问题的答案:
int main(void) { char *s = "hello world"; *s = 'H'; }