为什么取消引用 (char*)0 的 Linux 程序并不总是出现段错误? [英] Why does Linux program that derefrences (char*)0 not always segfault?

查看:13
本文介绍了为什么取消引用 (char*)0 的 Linux 程序并不总是出现段错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm testing code that is designed to detect when a child process has segfaulted. Imagine my surprised when this code does not always segfault:

#include <stdio.h>

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

我在 Debian Linux 2.6.26 内核下运行;我的 shell 是来自 Debian ksh 包的 AT&T ksh93,版本 M 93s+ 2008-01-31.有时这个程序会出现段错误,但否则它只是以非零退出状态但没有消息而静默终止.我的信号检测程序报告如下:

I'm running under a Debian Linux 2.6.26 kernel; my shell is the AT&T ksh93 from the Debian ksh package, Version M 93s+ 2008-01-31. Sometimes this program segfault but otherwise it simply terminates silently with a nonzero exit status but no message. My signal-detecting program reports the following:

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 under pure ksh shows that the segfault is also rare:

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

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

Interestingly, bash correctly detects the segfault every time.

我有两个问题:

  1. 谁能解释这种行为?

  1. Can anyone explain this behavior?

谁能推荐一个简单的 C 程序,在每次执行时都能可靠地发生段错误?我也尝试过kill(getpid(), SIGSEGV),但得到了类似的结果.

Can anyone suggest a simple C program that will segfault reliably on every execution? I have also triedkill(getpid(), SIGSEGV), but I get similar results.

<小时>

jbcreix 有答案:我的段错误检测器坏了.我被愚弄了,因为 ksh 有同样的问题.我尝试使用 bash 并且 bash 每次都正确.


jbcreix has the answer: my segfault detector was broken. I was fooled because ksh has the same problem. I tried with bash and bash gets it right every time.

我的错误是我将 WNOHANG 传递给 waitpid(),而我应该传递零.我不知道我当时在想什么!有人想知道 ksh 有什么问题,但这是一个单独的问题.

My error was that I was passing WNOHANG to waitpid(), where I should have been passing zero. I don't know what I could have been thinking! One wonders what is the matter with ksh, but that's a separate question.

推荐答案

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

Writing to NULL will reliably segfault or bus error.

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

Sometimes an OS will map a read-only page to the zero address. Thus, you can sometimes read from NULL.

虽然 C 将 NULL 地址定义为特殊地址,但该特殊状态的实现"实际上由操作系统的虚拟内存 (VM) 子系统处理.

Although C defines the NULL address as special, the 'implementation' of that special status is actually handled by the Operating System's Virtual Memory (VM) subsystem.

WINE 和dosemu 需要在NULL 处映射一个页面以实现Windows 兼容性.请参阅 Linux 内核中的 mmap_min_addr 以重建无法执行此操作的内核.

WINE and dosemu need to map a page at NULL for Windows compatibility. See mmap_min_addr in the Linux kernel to rebuild a kernel which cannot do this.

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

mmap_min_addr is currently a hot topic due to a related exploit and a public flame toward Linus (of Linux fame, obviously) from Theo de Raadt, of the OpenBSD effort.

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

If you are willing to code the child this way, you could always call: raise(SIGSEGV);

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

Also, you can obtain a guaranteed-to-segfault pointer from: 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.

Where PROT_NONE is the key to reserving memory which cannot be accessed. For 32-bit Intel Linux, PAGE_SIZE is 4096.

这篇关于为什么取消引用 (char*)0 的 Linux 程序并不总是出现段错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆