2012-02-22 12 views
3

ヌルポインタを参照解除すると、未定義の動作が発生します。実際には、通常は私のプログラムがクラッシュすることを意味します。しかし、なぜOSがクラッシュしないのですか?私のプログラムがヌルポインタを逆参照し、プログラムがOSによって実行されている場合、論理的な推移性の規則に従って、これはOSがヌルポインタを逆参照しようとしたことを意味します。 OSが「未定義の動作」状態に入るのはなぜですか?ヌルポインタを逆参照すると、OSがクラッシュしないのはなぜですか?

+2

OS *がクラッシュする可能性があるC++標準の観点からは、 – Flexo

+2

"実際にはプログラムがクラッシュする可能性があります。" - 違う。実際には、何か* ** **起こることができることを意味します。 – Xeo

+2

OSを書いた人は、自分が何をしているのか分かっていたからです。 – geoffspear

答えて

1

UBに関しては論理的な推移のルールはありません。あなたの前提は間違っています。

UBは何かが起こる可能性があることを意味します。そのため、OSが不適切に作成されていると、実際にOSがクラッシュする可能性があります。それを排除しないでください。

また、NULLポインタを参照解除するため、プログラムがクラッシュしません。それはOSがクラッシュするように指示するのでクラッシュします。

+0

2番目のステートメントはあなたの最初のステートメントと矛盾しているようです。 – StackedCrooked

+0

@StackedCrookedどのように表示されません。 –

+0

あなたは、プログラムのUB-nessがOSに影響を与える可能性があると言います。 – StackedCrooked

2

OSがの何かを実行する必要があり、クラッシュがかなり悪いユーザーエクスペリエンスになるためです。

OSがC標準の抽象マシン上で動作するように書かれていません。これは、標準が「未定義」と呼んでいるさまざまな状況に実際の方法で動作する実際のハードウェア向けに書かれているため、実際の動作を考慮に入れることができます。もしそうでなければ、オペレーティングシステムは異なるハードウェア上で異なる動作をしますが、これはOSを持つという目的を破るものですか?

「未定義の動作が定義されていないと、悪意のあるコードをユーザーに悪用させてもらいましょう」という前提で、サーバー全体をセグメンテーションできる偶発的なバッファオーバーランのセキュリティ上の問題を想像してください。

1

OSは、ヌルアドレスへのアクセスなど、メモリアクセスがOSによって課せられたルールに違反した場合に呼び出されるフォルトハンドラを設定します。あなたのプログラムがヌルポインタを逆参照しようとすると、このフォールトハンドラが呼び出され、プログラムは許可されていないメモリ領域にアクセスする前に終了します。だからあなたのプログラムは実際にヌルポインタを逆参照することはありません、試している間にキャッチされます。

禁止されたメモリアクセスを検出するメカニズムは、ページテーブルやメモリセグメンテーションなどのハードウェアサポートによって行われることがよくあります。

OSカーネル自体がヌルポインタを逆参照している場合は、その間に通常は中断されます。ブルースクリーン、カーネルのoopsなどが表示されます。それが継続すると、実際には "未定義の動作"が発生する可能性があります。

「未定義の動作」という用語は、C言語またはそれに類似する言語でのみ正確に定義されているため、プロセッサは実際には気にしません。通常、十分な権限がないメモリ領域アーキテクチャの文脈で非常によく定義されています。

+0

さて、* hardware *がこれを検出し、OSに信号を送ります(OSによって登録されたハンドラを呼び出します)。その後、OSはプログラムを強制終了することによってそれに反応します。 –

+0

@ ErnestFriedman-Hillハードウェアは、OS、プログラムの実行、メモリアドレス0へのアクセスの処理など、すべてを行います。 – hirschhornsalz

+0

あなたは、 "あなたがプログラムでヌルポインタを間接参照しようとしていることをOSが検出して終了します..."と言っています。ここでは、専用のメモリ管理ハードウェアがアクセスを検出してOSに通知し、それが実行されることを正しく指摘している他にもいくつかの答えがあります。あなたのプログラムが実行するすべての命令をOSが調べているかのようにはなりません。 –

2

まず、UBは「何かが起こる」ことを意味します。実際には近年のOSはメモリ保護を提供しています - プログラムに参照しようとすると、CPU内の割り込みをトリガし、OSとOSによって捕捉されて処理されたヌルポインタを逆参照してプログラムを停止し、何も悪いことが起こらなければ。

+0

私のC++プログラムからこの割り込みを処理できますか? – StackedCrooked

+0

@StackedCrooked、私が知る限り、捕まえられない唯一のシグナルはSIGKILL/SIGSTOP(私はsignal.h =を読んで編集)です。あなたはいつも読むことができます:man signal.h – Sebastian

+0

@StackedCrooked:これは実装に依存します。 Visual C++では、このようなケースが検出される可能性がありますが、賢明に処理することはできません。 – sharptooth

3

メモリアクセスはすべての主要OSで保護されています。割り当てられていないメモリを操作するプログラムを書くことは簡単ではありません(たとえば、ポインタが初期化されていないと仮定すると、すべてのアドレスになる可能性があります)。したがって、プログラムがそれに属していないアドレス空間にアクセスしようとするたびに、OSはプログラムを終了させる信号を送信します(結果として、C/C++プログラマーにとっては馴染み深い「セグメンテーション・フォールト」になります)。

+0

+1私はこの時私は私のwrittingだった。 StackOverflowは回答を自動更新する必要があります。 – Sebastian

10

C++標準では、クラッシュを保証するため、またはその他のことを行うための動作が定義されていません。これは、OSが動作を定義することを妨げるものではありません.C++プログラムではないため、C++プログラムの "規則" [1]を守る必要はありません。それでも、OSはポインタそのものを逆参照しません。

ほとんどの最新のプラットフォームでは、逆参照されたポインタのターゲットにアクセスすると、メモリ管理ハードウェアが例外を発生させます(「セグメント化エラー」または「保護フォルト」と呼ばれることがあります)。これはカーネルがキャッチします。カーネルはどのプロセスがプロセスを終了したかを判断し、プロセスを終了させるか、シグナルを送信します。

したがって、このようなプラットフォームでは、ヌルポインタを逆参照するプロセスのデフォルトの動作はクラッシュすることになります。 OS自体がクラッシュする理由はありません。

[1]私は非公式の「ルール」を意味これにより、プログラムがうまく形成することと、未定義の動作を避ける必要があること - 言語標準で指定されたC++の実装のための正式な「ルール」と混同してはなりません。論理的推移の規則に従って、そして、私のプログラムは、NULLポインタを逆参照し、私のプログラムは、OSによって 実行されるため場合

+1

ポインタ自体を逆参照する行為は、C++で参照を取得するだけなので、セグメンテーションを発生させないことに注意してください。しかし、nullポインタ(または参照)を介して何かにアクセスすることはできます。 – Xeo

+0

@ Xeo:確かに、私は「間接参照」という言葉を少しゆっくり使っていました。 –

+0

* "これはC++プログラムではないので、C++プログラムのルールに従う必要はありません"と私は許していますが、その文は意味をなさない。 C++ **は*** "未定義の動作"を必要としません。単に行動を定義していないと主張しているだけです。他の誰かが非常にうまくいくかもしれません。 OSが書かれている言語は無関係です(とにかく、C++があなたのポイントに完全に逆らっていなければ、Cの可能性が高いという事実)。あなたはその文を完全に削除するだけで、投稿はそれなしで意味をなさないでしょう。 – Mehrdad

0

、 これはOSがNULLポインタデリファレンスしようとしたことを意味します。 OSに「未定義の動作」の状態が入力されないのはなぜですか?

これは間違っています。メモリ保護と呼ばれるものがあり、プログラムが終了する理由は何ですか。 OS自体が(メモリ使用の点で)保護していますか?

0

申し訳ありませんが、どのような '論理的な推移'のルールですか?オペレーティングシステムが設計することの1つは、他のプログラムの不正行為からプログラムを保護することです。特に、あなたのプログラムが何かばかげたことをしようとしているだけなので、O/Sはクラッシュするべきではありません。

メモリ保護のないオペレーティングシステムでは、null(または無効な)ポインタを使用してアクセスすると、実際にO/Sがクラッシュする可能性があります(O/Sで何か面白いものが使用された場合)。

しかし、これは論理的な推移性とは関係ありません。それはあなたのプログラムが別のプログラムに属するメモリにアクセスすることと関係しています。いずれのプログラムも、こうした状況でクラッシュする可能性があります。

1

プログラムのほとんどは、ユーザーモードで実行され、OSがカーネルモードで実行されるため。カーネルモードは、物理的なハードウェアの近くにあります(に近いと言います)。カーネルモードプログラム(OS、いくつかのサービス、ドライバなど)は、CPUのリング0で実行されます。ユーザーモードプログラムは、高い音量で動作します。 CPUのリングNで実行されているユーザーモードプログラムは、N以下のプログラムやメモリにアクセスすることはできません。試してみると、許可されません!

すべてのプログラムが論理アドレスを取得し、OSが割り当てます。 OSは、プログラムがメモリを読み書きしようとすると、論理から物理へのアドレッシングを行います。プログラムがアクセス権を持っていないアドレスにアクセスしようとすると、OSは例外をスローします。この例外は、プログラム自体(同じスレッド内のローカル例外ハンドラ)によって処理される場合があります。そうでなければ、接続されたグローバル例外ハンドラ。デバッガは、ローカルのEHがそれを処理しない場合、画像になることもあります。これは、OS、デバッガに例外をルーティングする方法、および/またはグローバル例外ハンドラに依存します。 OSがローカル/グローバル/デバッガで処理できるかどうかは、(NULLポインタへのアクセスのような)例外のタイプにも依存します。誰もそれを処理しなければ、OSはプロセスを終了させます(そしておそらく、クラッシュダンプ、セグメンテーションフォールトのコアダンプを作成します)。

プロセスがデバッグされていない(Windows固有)場合、一部のデバッガがインストールされていると、OSによってユーザーがデバッグできるようになる場合があります。

カーネルモードプログラムが不快なことをすると、OSがダウンします。私はLinuxの人ではないので、Linuxの動作を知らない。しかし、Windowsの場合、BSODはあなたのモニターを青色で明るくするでしょう!

関連する問題