6

子プロセスがsegfaultされたことを検出するように設計されたコードをテストしています。このコードが常にセグメンテーション違反ではないことに驚いたと想像してみてください。

#include <stdio.h>

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

私はDebianLinux2.6.26カーネルで実行しています。私のシェルはksh93DebiankshパッケージのAT&T、バージョン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と、セグメンテーション違反もまれであることがわかります。

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

興味深いことに、bash毎回セグメンテーション違反を正しく検出します。

2つの質問があります:

  1. 誰かがこの振る舞いを説明できますか?

  2. 実行のたびに確実にセグメンテーション違反を起こす単純なCプログラムを誰かが提案できますか?私も試しkill(getpid(), SIGSEGV)ましたが、同様の結果が得られました。


編集:jbcreixには答えがあります:私のセグメンテーション違反検出器が壊れていました。ksh同じ問題があるので私はだまされました。私は試してみてbashbash毎回それを正しくしました。

私のエラーは、私がゼロを通過するはずだった場所に通過WNOHANGしていたことでした。waitpid()何を考えていたのかわからない!何が問題なのか疑問に思う人もいますがksh、それは別の質問です。

4

3 に答える 3

12

に書き込むと、NULL確実にセグメンテーション違反またはバスエラーが発生します。

OSが読み取り専用ページをゼロアドレスにマップする場合があります。したがって、から読み取ることができる場合がありますNULL

CはNULLアドレスを特別なものとして定義していますが、その特別なステータスの「実装」は、実際にはオペレーティングシステムの仮想メモリ(VM)サブシステムによって処理されます。

WINEとdosemuはNULL、Windowsとの互換性のためにページをマップする必要があります。mmap_min_addrこれを実行できないカーネルを再構築するには、Linuxカーネルを参照してください。

mmap_min_addrOpenBSDの取り組みのTheodeRaadtからのLinus(明らかにLinuxの名声)に対する関連するエクスプロイトと公の炎のために、現在ホットなトピックです。

この方法で子をコーディングする場合は、いつでも次のように呼び出すことができます。raise(SIGSEGV);

また、セグメンテーション違反が保証されているポインタは、次の場所から取得できます。 int *ptr_segv = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, -1, 0);

PROT_NONEアクセスできないメモリを予約するための鍵はどこにありますか。32ビットIntelLinuxの場合、PAGE_SIZEは4096です。

于 2009-11-14T19:43:08.760 に答える
1

なぜ一貫した動作がないのかわかりません。私はそれが読書でそれほどつまらないものではないと思います。またはそのようなものですが、私はおそらく完全に間違っているでしょう。

NULLで書いてみてください。これは私にとって一貫しているようです。なぜこれを使いたいのか分かりませんが。:)

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

ウィキペディアの質問2への回答:

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